原来Flutter代码是这样运行在原生系统的!快来了解Flutter标准模板,感受原生系统中Flutter的魅力!

简介: 原来Flutter代码是这样运行在原生系统的!快来了解Flutter标准模板,感受原生系统中Flutter的魅力!

通过Android Studio创建的Flutter应用模板,了解Flutter项目结构,分析Flutter工程与原生Android和iOS工程有哪些联系,体验一个有着基本功能的Flutter应用是如何运转的,从而加深你对构建Flutter应用的关键概念和技术的理解。


Dart只要理解基本编程概念(比如,类型、变量、函数和面向对象),并具备一定前端基础(了解View是什么、页面基本布局等基础),就可以和我一起完成计数器示例工程分析


Android Studio创建Flutter工程应用flutter_app。Flutter会根据自带的应用模板,自动生成简单计数器示例应用Demo。我们先运行此示例,效果如下:

每点击一次右下角带“+”号的悬浮按钮,就可以看到屏幕中央的数字随之+1。

1 工程结构

了解Flutter工程与原生Android和iOS工程关系及这些关系是如何确保Flutter程序最终运行在Android和iOS。

除Flutter本身的代码、资源、依赖和配置,Flutter工程包含Android和iOS工程目录。因为Flutter虽然是跨平台开发方案,但却需要一个容器最终运行到Android和iOS平台,所以 Flutter工程实际是同时内嵌Android和iOS原生子工程的父工程:在lib目录进行Flutter代码开发,某些特殊场景原生功能,则在对应Android和iOS工程提供相应代码实现,供对应Flutter代码引用。


Flutter会将相关依赖和构建产物注入这两个子工程,集成到各自项目。而我们开发Flutter代码,最终以原生工程形式运行。

2 工程代码

Flutter自带的应用模板,即计数器示例,对初学者是极好入门范例。从基础的组件、布局到手势的监听,再到状态的改变,Flutter最核心思想在这60余行代码。

为便学习理解,删掉核心流程无关组件配置代码及布局逻辑,不影响示例功能的情况下对代码进行改写,并分两部分:

  • 应用入口、应用结构以及页面结构,理解构建Flutter程序的基本结构和套路
  • 页面布局、交互逻辑及状态管理,理解Flutter页面是如何构建、如何响应交互,以及如何更新

3 第一部分代码,应用的整体结构

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(home: MyHomePage(title: 'Flutter Demo Home Page'));
}
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  Widget build(BuildContext context) => {...};
}

Flutter应用为MyApp类的一个实例,MyApp类继承自StatelessWidget类,即应用本身也是一个Widget。Flutter中的Widget是整个视图描述的基础,Flutter中的包括应用、视图、视图控制器、布局等概念,都建立在Widget之上,Flutter核心设计思想是一切皆Widget。

3.1 Widget

组件视觉效果的封装,UI界面的载体,因此还要为它提供一个方法,告诉Flutter框架如何构建UI界面,即build。

3.1.1 build方法

通过对基础Widget进行相应UI配置或组合各类基础Widget进行UI定制化。如MyApp通过MaterialApp这个Flutter App框架设置应用首页,即MyHomePage。

3.2 MaterialApp类

是对构建material设计风格应用的组件封装框架,有很多可配置属性,如应用主题、应用名称、语言标识符、组件路由等,可参考Flutter官方的 API文档,了解MaterialApp框架的其他配置能力。

3.3 MyHomePage

应用首页,继承自StatefulWidget类,有状态Widget(Stateful Widget), _MyHomePageState就是其状态。


虽然MyHomePage类也是Widget,但与MyApp类不同,它没有build方法返回Widget,而是多个createState方法返回_MyHomePageState对象,而build方法包含在这 _MyHomePageState 类中。

3.4 StatefulWidget V.S StatelessWidget的接口设计

因为Widget要依据数据才能完成构建,对StatefulWidget来说,其依赖的数据在Widget生命周期中可能频繁变化。由State创建Widget,以数据驱动视图更新,而非直接操作UI更新视觉属性,代码表达更精炼,逻辑更清晰。


4 第二部分-页面布局及交互逻辑

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  void _incrementCounter() => setState(() {_counter++;});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(Widget.title)),
      body: Text('You have pushed the button this many times:$_counter')),
      floatingActionButton: FloatingActionButton(onPressed: _incrementCounter)
    );
  }

_MyHomePageState中创建的Widget Scaffold,是Material库提供的页面布局结构,包含:

  • AppBar,页面导航栏,直接将MyHomePage中的title属性作为标题使用
  • body,Text组件,显示了一个根据_counter属性可变的文本:‘You have pushed the button this many times:$_counter’。

floatingActionButton,页面右下角的“+”悬浮按钮。将 _incrementCounter 作为其点击处理函数

_incrementCounter

使用setState方法自增状态属性_counter。setState方法是Flutter以数据驱动视图更新的函数,会通知Flutter框架:我这儿有状态改变,赶紧给我刷新界面!而Flutter框架收到通知后,会执行Widget#build,根据新状态重建界面。


状态的更改一定要配合使用setState。通过该方法调用,Flutter会在底层标记Widget的状态,随后触发重建。示例即使修改_counter,若不调用setState,Flutter框架也不会感知到状态变化,因此界面也不会有任何改变。


图计数器示例的代码流程示意图,把这实例的整个代码流程串起:

MyApp为Flutter应用的运行实例,在main函数中调用runApp函数实现程序的入口。

应用首页则为MyHomePage,一个拥有_MyHomePageState状态的StatefulWidget。_MyHomePageState通过调用build方法以相应数据配置完成包括导航栏、文本及按钮的页面视图的创建。


而当按钮被点击之后,其关联的控件函数_incrementCounter会触发调用。在这个函数中,通过调用setState更新_counter属性同时,也通知Flutter框架其状态发生变化。随后,Flutter重新调用build方法以新数据配置重建_MyHomePageState的UI,最终完成页面重新渲染。


Widget只是视图的“配置信息”,是数据的映射,“只读”。对StatefulWidget,当数据改变时,需重建Widget去更新界面,即Widget创建销毁会很频繁。


为此,Flutter对此机制

5 优化

其框架9内部会通过一个中间层收敛上层UI配置对底层真实渲染的改动,从而最大程度降低对真实渲染视图的修改,提高渲染效率,而不是上层UI配置变就要销毁整个渲染视图树重建。


这样Widget仅是一个轻量级的数据配置存储结构,它的重新创建速度非常快,所以我们可放心重建任何需更新的视图,无需分别修改各子Widget特定样式。

6 总结

先通过Flutter标准模板创建了计数器示例,并分析了Flutter的项目结构,以及Flutter工程与原生Android、iOS工程的联系,知道了Flutter代码是怎么运行在原生系统上的。


然后,学习示例项目代码,了解了Flutter应用结构及页面结构,并认识了构建Flutter的基础,也就是Widget,以及状态管理机制,知道了Flutter页面是如何构建的,StatelessWidget与StatefulWidget的区别,以及如何通过State的成员函数setState以数据驱动的方式更新状态,从而更新页面。


有原生Android和iOS框架开发经验的同学,可能更习惯命令式UI编程风格:手动创建UI组件,在需要更改UI时调用其方法修改视觉属性。而Flutter采用声明式UI设计,只需描述当前UI状态(即State),不同UI状态的视觉变更由Flutter在底层完成。


虽然命令式的UI编程风格更直观,但声明式UI编程方式好处是,可以让我们把复杂的视图操作细节交给框架去完成,这样一来不仅可以提高我们的效率,也可专注整个应用和页面的结构和功能。

7 FAQ

示例项目代码在_MyHomePageState类中,直接在build函数里以内联的方式完成了Scaffold页面元素的构建,这样做的好处是什么呢?在实现同样功能的情况下,如果将Scaffold页面元素的构建封装成一个新Widget类,我们该如何处理?


将Scaffold页面元素的构建封装成一个新Widget类的好处是可以提高代码的可复用性和可维护性。这样可以将Scaffold的构建逻辑封装到一个独立的组件中,方便在其他地方重复使用,也方便后续进行修改和维护。


如果要将Scaffold页面元素的构建封装成一个新Widget类,可以创建一个新的StatelessWidget或StatefulWidget类,然后在该类的build方法中返回Scaffold组件的代码。这样就可以在其他地方使用该组件来构建Scaffold页面元素。例如:

class MyScaffold extends StatelessWidget {
  final Widget body;
  const MyScaffold({Key? key, required this.body}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
      body: body,
    );
  }
}

然后在其他地方可以通过MyScaffold来构建页面元素,例如:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MyScaffold(
      body: Center(
        child: Text('Hello, World!'),
      ),
    );
  }
}
目录
相关文章
|
7月前
|
iOS开发
Flutter与iOS原生通信方式
Flutter与iOS原生通信方式
315 2
|
2天前
|
编解码 算法 开发者
Flutter的布局系统:深入探索布局Widget与布局原则
【4月更文挑战第26天】Flutter布局系统详解,涵盖布局Widget(Row/Column、Stack、GridView/ListView、CustomSingleChildLayout)和布局原则(弹性布局、约束优先、流式布局、简洁明了)。文章旨在帮助开发者理解并运用Flutter的布局系统,创建适应性强、用户体验佳的界面。通过选择合适的布局Widget和遵循原则,可实现复杂且高效的UI设计。
|
3月前
|
机器学习/深度学习 Java Android开发
记录一个Flutter运行的异常FAILURE: Build failed with an exception. What went wrong: A problem occurred config
记录一个Flutter运行的异常FAILURE: Build failed with an exception. What went wrong: A problem occurred config
46 0
|
3月前
|
存储 Dart 前端开发
为什么说 Compose 的声明式代码最简洁 ?Compose/React/Flutter/SwiftUI 语法对比
为什么说 Compose 的声明式代码最简洁 ?Compose/React/Flutter/SwiftUI 语法对比
57 1
|
6月前
|
Dart Android开发
Flutter | vscode运行Flutter疑难杂症
本来今天更新Stable Diffusion最后一个教程的,但是今天在开发中遇到了一个问题。
Flutter | vscode运行Flutter疑难杂症
|
6月前
|
Dart 编译器 开发工具
Flutter | windows使用vscode创建并使用夜神模拟器运行flutter
开发Flutter如果使用Android studio并运行,编译器加上虚拟机基本上直接占用2个多G内存,对于16G内存的电脑来说,压力还是有点大的。所以如果使用vscode开发是不是好很多,而且还用的顺手。
156 0
|
7月前
|
Dart 开发工具 Android开发
Flutter与iOS原生混合开发
Flutter与iOS原生混合开发
348 2
|
7月前
|
JavaScript Java 关系型数据库
基于微服务、SpringBoot、Vue、Flutter、MySQL智慧工地系统源码
B/S架构,两个终端:PC后台管理端、APP移动端 基于微服务、Java、SpringBoot、Vue、Flutter、MySQL开发的智慧工地系统源码
|
9月前
|
开发框架 Dart 开发工具
使用Flutter开发一套可同时运行在Android和iOS平台的代码
Flutter是一种跨平台移动应用开发框架,它允许开发者使用单一代码库构建高性能、美观且可在多个平台上运行的应用程序。本文将介绍如何使用Flutter开发一套同时适用于Android和iOS平台的代码。
|
10月前
|
Android开发 iOS开发
Flutter应用开发,系统样式改不了?SystemChrome 状态栏、导航栏、屏幕方向……想改就改
Flutter应用开发,系统样式改不了?SystemChrome 状态栏、导航栏、屏幕方向……想改就改