Flutter有三种运行模式
debug 调试模式
profile 分析模式
release 运行模式
调试模式特点:
原生平台:
启用断言
启用调试
编译针对快速开发和运行周期进行了优化(但不针对执行速度、二进制大小或部署)。
网络应用程序
构建没有缩小
该应用程序使用 dartdevc 编译器进行编译,以便于调试。
release模式
基本上就是调试模式反过来
原生版本
web版本
该应用程序是用 dart2js 编译器编译的,以获得最佳性能。
分析模式
容易想到,分析模式和发布模式很接近,就是附近了分析服务或工具
注意第一次在物理设备上运行时,可能需要一段时间才能加载。
pubspec.yaml 是 Flutter 项目的配置文件,类似于 Android 中的 Gradle 配置文件,下面我们就看看 pubspec.yaml 中各个属性的配置。
创建一个新的项目(Flutter Application),pubspec.yaml 位于根目录,如图:
Flutter基于渲染引擎 Skia,Skia 是一款用 C++ 开发的、性能彪悍的 2D 图像绘制引擎,其前身是一个向量绘图软件。目前是Android和
Chrome的官方渲染引擎。Flutter打包这两个平台的时候不用打包Skia了,然后IOS等就需要打包,所以打包体积会大些。
然后因为基于Skia,所以Flutter的绘图API和Android是比较像的。
参考资料 : https://juejin.cn/post/6844903784187953165
在 Flutter 中,几乎所有东西都是小部件,包括对齐、填充和布局。
首先,响应式编程和异步编程有关系,异步编程就是发出一个任务,不用等待结果,而是执行其它代码,然后通过某种方式监听到任务结果并对其进行处理。
响应式编程是使用异步数据流进行编程
异步数据流可以是各种事件的数据组成的列表,比如点击,用户输入,IO数据输入,处理运算结果等,但是它们是异步到来的。
响应式编程提高了代码的抽象层级,我们不必关注这些异步处理的细节,只需要把这个异步数据流当成一个数据列表一样处理,可以map,filter、处理这些数据流。
(几乎) 所有的东西都可以转为一个Stream 。这就是Rx的咒语。
widget是flutter的核心类,作用类似于原生的View,用于构建UI界面。但是其内部原理有所不同。
Flutter Widget 采用现代响应式框架构建, Widget描述了他们的视图在给定其当前配置和状态时应该看起来像什么。
在 Fultter 中,每一个 Widget 都是被唯一标识的。这个唯一标识在 build/rendering 阶段由框架定义。
该唯一标识对应于可选的 Key 参数。如果省略该参数,Flutter 将会为你生成一个。
在某些情况下,你可能需要强制使用此 key,以便可以通过其 key 访问 widget。
为此,你可以使用以下方法中的任何一个:GlobalKey、LocalKey、UniqueKey 或 ObjectKey。
GlobalKey 确保生成的 key 在整个应用中是唯一的。
强制 Widget 使用唯一标识:
GlobalKey myKey = new GlobalKey();
…
@override
Widget build(BuildContext context){
return new MyWidget(
key: myKey
);
}
这个就类似于Android中的view id了
Widget 以树结构进行组织。
包含其他 Widget 的 Widget 被称为父 Widget(或Widget 容器)。包含在父 Widget 中的 Widget 被称为子 Widget。
flutter中使用小部件树 widget tree来实现布局编写。
让我们用 Flutter 自动生成的基础应用来说明这一点。以下是简化代码,仅有 build 方法:
@override
Widget build(BuildContext){
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
如果我们现在观察这个基本示例,我们将获得以下 Widget 树结构(限制代码中存在的 Widget 列表)
另外一个重要的概念是 Context。
Context 仅仅是已创建的所有 Widget 树结构中某个 Widget 的所占区域的引用。
如果我们现在尝试在上图中说明 Context 的概念,我们得到(依旧是一个非常简化的视图)每种颜色代表一个 context(除了 MyApp,它是不同的):
这些可视化组件除了它们自身的配置信息外不依赖于任何其他信息,该信息在其直接父节点构建时提供。
换句话说,这些 Widget 一旦创建就不关心任何变化。
这样的 Widget 称为 Stateless Widget。
当所描述的用户界面部分不依赖于对象中的配置信息以外的任何东西时,StatelessWidgets 非常有用。
Stateless Widget 的生命周期是相当简单的:
初始化
通过 build() 渲染
该 Widget 所持有的数据集在其生命周期内可能会发生变化,这样的数据被称为 State。
如果我们使用有状态widget,当widget的状态发生变化时,widget会重新构建UI 注意Android需要手动调用Invalid才重新绘制,Flutter会对比前后变化的不同, 以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。Flutter 不会改变旧的实例 b,而是构造新的 Widget 实例。框架使用 RenderObjects 在后台完成传统 UI 对象的许多职责(比如维护布局的状态)。
注意:Flutter 的小部件是轻量级的,部分原因在于它们的不变性。因为它们不是视图本身,也不直接绘制任何东西,而是对 UI 及其语义的描述,渲染的时候这些描述被“膨胀”成了实际的视图对象。
Stateful Widget 由 2 部分组成
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({
Key key,
this.color,
}): super(key: key);
final Color color;
@override
_MyStatefulWidgetState createState() => new _MyStatefulWidgetState();
}
第一部分 “MyStatefulWidget” 通常是 Widget 的 public 部分。当你需要将其添加到 widget 树时,可以实例化它。该部分在 Widget 生命周期内不会发生变化,但可能接受与其相关的 State 实例化时使用的参数。
请注意,在 Widget 第一部分定义的任何变量通常在其生命周期内不会发生变化。
class MyStatefulWidgetState extends State {
…
@override
Widget build(BuildContext context){
…
}
}
“MyStatefulWidgetStat” 管理 Widget 生命周期中的变化,并强制每次应用修改时重建该 Widget 实例。名称开头的 ‘’ 字符使得该类对 .dart 文件是私有的。
如果你需要在 .dart 文件之外引用此类,请不要使用 ‘’ 前缀。
_MyStatefulWidgetState 类可以通过使用 widget.{变量名称} 来访问被存储在 MyStatefulWidget 中的任何变量。在该示例中为:widget.color。
一旦 State 对象被创建,initState() 方法是第一个(构造函数之后)被调用的方法。当你需要执行额外的初始化时,该方法将会被重写。常见的初始化与动画、控制器等相关。如果重写该方法,你应该首先调用 super.initState()。
build(BuildContext context) 方法在 didChangeDependencies()(及 didUpdateWidget)之后被调用。
这是你构建你的 widget(可能还有任何子树)的地方。
每次 State 对象更新(或当 InheritedWidget 需要通知“已注册” widget)时都会调用该方法!!
通过setState传递一个类似于run的函数进入,框架就会run这个函数,然后调用build函数构建widget,刷新界面
didChangeDependencies() 方法是第二个被调用的方法。
在这一阶段,由于 context 是可用的,所以你可以使用它。
如果你的 Widget 链接到了一个 InheritedWidget 并且/或者你需要初始化一些 listeners(基于 context),通常会重写该方法。
请注意,如果你的 widget 链接到了一个 InheritedWidget,在每次重建该 Widget 时都会调用该方法。
如果你重写该方法,你应该首先调用 super.didChangeDependencies()。
dispose() 方法在 widget 被废弃时被调用。
如果你需要执行一些清理操作(比如:listeners),则重写该方法,并在此之后立即调用 super.dispose()。
有时,父 widget 可能需要访问其直接子节点的 State 才能执行特定任务。
在这种情况下,要访问这些直接子节点的 State,你需要了解它们。
呼叫某人的最简单方法是通过名字。在 Flutter 中,每个 Widget 都有一个唯一的标识,由框架在 build/rendering 时确定。如前所示,你可以使用 key 参数为 Widget 强制指定一个标识。
…
GlobalKey myWidgetStateKey = new GlobalKey();
…
@override
Widget build(BuildContext context){
return new MyStatefulWidget(
key: myWidgetStateKey,
color: Colors.blue,
);
}
复制代码一经确定,父 Widget 可以通过以下形式访问其子节点的 State:
myWidgetStateKey.currentState
小部件的主要工作是提供一个 build ()方法,该方法描述如何按照其他较低级别的小部件来显示小部件。