1一切皆为widget
flutter 和Android 有所不一样,android包含 布局(各种layout),组件(button,textview 等等);flutter的一切都是widget,包括最顶层的页面布局都是一个widget,包含许多其他的widget,一个页面则有多个widget组合而成.
widget 根据不同的功能可以分为:
- 结构元素(如按钮或菜单)
- 文本样式(字体或者颜色方案)
- 布局的一种(如填充,对齐,居中)
-
...
事实上可以理解成,一个flutter的页面是有一棵树型的widget组成,包括根节点,和树枝,树叶都是 一个widget, widget嵌套其他的widget而已.对于一些Android中的属性值,例如 对齐方式,居中,padding,在flutter中都是一个widget.
通常我们app中会使用到两种 widget, statelessWidget 和statefulWidget 表示无状态widget和有状态widget.
2 statefulwidget
- statefulwidget :这些widget需要根据用户的交互或者其他因素进行更改.通常一个statefulwidget 会包含一个State 状态,需要改变状态的值可以State.setState 方法.对于statefulWidget中的状态值,可以重写 creatState时初始化的,或者是在有订阅State的对象中(例如Stream,ChangeNotifier 等对象).flutter框架会在生成StatefulWidget树的时候调用creatState.
StatefulWidget,如果在构造器钟使用了GlobalKey 表示key的时候,在进行移动到另一颗树的时候,会保持状态对象不会改变.因为拥有GlobalKey的widget在整个树形结构中只会放在一个位置,使用GlobalKey的widget则会关联这个元素.
2.1 StatefulWidget两个基本类型
- 1 第一个类型: 和资源相关,在初始化时调用
State.initState
准备使用的时候调用State.dispose
,但是它不依赖与InheritedWidget
也不需要调用State.setState
.这些widget广泛使用在app或者一个页面的root,通过ChangeNotifier
,Stream
或者其他对象和他的子widget通讯.有状态的widget遵循这样的模式相对来说比较低耗(根据cpu和gpu的周期讲)因为他们只需要编译一次后面就不需要更新.因此他们可以做一些复杂深层的构建方法. - 2 第二种类型: 使用
State.setState
或者依赖InheritedWidget
的widget.这些widget典型的会在app的生命周期中重新构建多次,因此对widget重新构建最小化影响显得尤为重要.(也可以使用State.initState
或者State.didChangeDependencies
分配资源,但是最重要的还是重新构建渲染)
有一些可以减少statefulwidget重新构建的技术手段:
- 把state push到树结构的叶子上,而不是根节点.例如,如果你的page有一个秒钟,创建一个clock widget来处理更新的状态,而不要在page的顶层(根节点)中放置state.
- 最小化通过build,和任何widget创建的结点树.
- 如果子树不需要改变,缓存表示子树的widget,并在每次需要使用的时候重用.重用比重新构建更有效
- 尽可能使用
const
widget.(作用和使用缓存widget并且重用它的一样) - 避免改变已经创建好的子树的深度,或者改变创建好的子树的widget的类型.可以通过用
IgnorePointer
来包装widget,并且控制IgnorePointer.ignoring
.这是因为,改变子树的深度需要进行widget的重构,重新布局,并且重绘子树的实体,而改变属性只需要尽小可能的改变树的渲染(例如IgnorePointer
,不需要重新布局,和重绘子树的实体) - 由于某些原因如果确实需要进行改变widget的深度,考虑包装widget子树的common 部分,让其采用
GlobalKey
3.Statelesswidget
statelesswidget是一个小部件,具体地说是用于描述用户界面的一部分构建描述用户界面的其他小部件的宿主。 构建过程以递归方式继续,直到用户界面的描述是完全具体的(例如,包含完全是RenderObjectWidget
,它描述了具体的RenderObject
)
当您是用户界面的一部分时,statelesswidget非常有用描述不依赖于配置以外的任何其他内容对象本身的信息和widget inflate的BuildContext
。 对于可以动态改变的组合物,例如 由于具有内部时钟驱动状态,或取决于某些系统状态,考虑使用StatefulWidget
3.1性能考虑
statelesswidget 的build
方法通常仅在三个中调用情况:第一次将widget插入树中,当时widget的父级更改其配置,当[InheritedWidget]依赖于更改时。
如果widget的父级将定期更改widget的配置,或者如果它取决于经常改变的继承widget,这样优化[build]方法的性能以维持流畅渲染性能就变得很重要。
3.2 技术优化手段:
- 对任何widget最小化构建方法和创建的节点数量。 例如,考虑只使用
Align
或CustomSingleChildLayout
而不是精心安排Row
,Column
,Padding
和SizedBox
来以特别花哨的方式定义child。 考虑一个CustomPaint
小部件而不是复杂的多层次Container
和Decoration
用于绘制正确的图形效果。 - 尽可能使用
const
widget. - 考虑将statelessWidget重构为statefulwidget它可以使用
StatefulWidget
中描述的一些技术,例如缓存子树的公共部分并在更改时使用GlobalKey
树的结构。
class GreenFrog extends StatelessWidget {
const GreenFrog({ Key key }) : super(key: key);
@override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFF2DBD3A));
}
}
class Frog extends StatelessWidget {
const Frog({
Key key,
this.color: const Color(0xFF2DBD3A),
this.child,
}) : super(key: key);
final Color color;
final Widget child;
@override
Widget build(BuildContext context) {
return new Container(color: color, child: child);
}
}
按照惯例,widget构造函数仅使用命名参数。 命名参数可以使用@required
标记为必需。 按照惯例,第一个参数是key
,最后一个参数是child
,children
或者相似的。