文章目录
基础知识
Flutter
中我们往往会听到如下几个类:
Widget
Element
RenderObject
我们来分别讨论下他们的作用:
Widget
用于描绘你的视图长什么,相当于一个建造楼房的蓝图。
内部存在函数用于生成Element
和RenderObject
.
class Widget{
//生成Element
Element createElement();
}
//Widget自类生成渲染器对象
class RenderObjectWidget extends Widget {
RenderObject createRenderObject(BuildContext context);
}
RenderObject
将Widget
设计绘制到屏幕中,再往下便是底层绘制引擎,这个对象被Element
持有引用。
Element
持有Widget
和RenderObject
,决定Widget
描绘的层次与提高绘制性能。可以简单理解这个类用RenderObject
来渲染所关联的Widget
,并且内部有优化机制决定是否更新渲染。
WidgetTree
Flutter
视图由一个个Widget
组合而来得到最终的渲染蓝图。
如下图:
ElementTree
每一个Widget
会生成对应的Element
,最后这些生成的Element
也会形成一个树。
RenderTree
Tip: 部分Widget没有RenderObject对象,而是来自子树的。读者可自行深入
简单抽象关系图
Element
会持有两个对象的引用:
如果Widget
是StatefulWidget
那么Element
还会持有对应的State
类
绘制极简流程
StatefulWidget
绘制
StatefulWidget
绘制设计蓝图是位于State
类的build
函数返回。
class MyStateWidget extends StatefulWidget {
@override
_MyStateWidgetState createState() => _MyStateWidgetState();
}
class _MyStateWidgetState extends State<MyStateWidget> {
//决定绘制的蓝图
@override
Widget build(BuildContext context) {
return Container();
}
}
绘制教程:
StatefulWidget
系统会调用createElement
生成一个Element
class StatefulElement extends ComponentElement {
@override
Widget build() => _state.build(this);
}
tip: 以上顺序笔者并没有严格阅读源码,可能存在错误请注意!! - -其实是不想看
StatelessWidget
绘制
小结
我们的StatelessWidget
和StatefulWidget
中的build
函数的返回的上下文就是element
.
StatelessWidget
自己的build函数返回视图的配置信息给Render
对象进行绘制。
StatefulWidget
使用状态类state的build返回的视图配置给Render
对象进行绘制
Widget的key
Widget
存一个属性key
,在构造时可以传入。默认null
.
key
主要的作用的是用来判断当 WidgetTree
发生了移动删除后,ElementTree
对应的Element
是否需要更新对Widget
的引用,或移动某个Element
在WidgetTree
的位置,以及是否销毁重建。具体可以看 参考1
GlobalKey和LocalKey的区别
仅讨论StatefulWidget
LocalKey
当两个Widget在同一个父级时且做一次交换位置,那么element
不会删除重建,只会根据状态更新引用或者交换ElementTree的元素位置,如果两个Widget不属于同一个父级那么会删除Element
节点重建。
如下例子:
点击按钮交换两个Widget的位置(UniqueKey
是LocalKey
子类)
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'UniqueColorGenerator.dart';
void main() => runApp(new MaterialApp(home: PositionedTiles()));
class PositionedTiles extends StatefulWidget {
@override
State<StatefulWidget> createState() => PositionedTilesState();
}
class PositionedTilesState extends State<PositionedTiles> {
List<Widget> tiles = [
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [StatefulColorfulTile(key: UniqueKey())],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [StatefulColorfulTile(key: UniqueKey())],
),
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(children: tiles),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.sentiment_very_satisfied), onPressed: swapTiles),
);
}
swapTiles() {
setState(() {
tiles.insert(1, tiles.removeAt(0));
});
}
}
class StatelessColorfulTile extends StatelessWidget {
Color myColor = UniqueColorGenerator.getColor();
@override
Widget build(BuildContext context) {
debugPrint(
"StatelessColorfulTile ${this.hashCode} 重新build element ${context.hashCode} ${this.createElement() == context}");
return Container(
margin: EdgeInsets.only(top: 50),
color: myColor,
child: Padding(padding: EdgeInsets.all(70.0)));
}
}
class StatefulColorfulTile extends StatefulWidget {
StatefulColorfulTile({Key key}) : super(key: key); // NEW CONSTRUCTOR
@override
ColorfulTileState createState() {
debugPrint(
"StatefulColorfulTile ${this.hashCode} 重新createState");
return ColorfulTileState();
}
}
class ColorfulTileState extends State<StatefulColorfulTile> {
Color myColor;
@override
void initState() {
super.initState();
myColor = UniqueColorGenerator.getColor();
}
@override
Widget build(BuildContext context) {
debugPrint(
"ColorfulTileState ${this.hashCode} 重新build element ${context.hashCode} widget: ${widget.hashCode}");
//
return Container(
color: myColor,
child: Padding(
padding: EdgeInsets.all(70.0),
));
}
}
多次点击按钮的日志:
flutter: StatefulColorfulTile 731559728 重新createState
flutter: ColorfulTileState 940397615 重新build element 202 widget: 731559728
flutter: StatefulColorfulTile 318147042 重新createState
flutter: ColorfulTileState 967144222 重新build element 206 widget: 318147042
flutter: StatefulColorfulTile 318147042 重新createState
flutter: ColorfulTileState 54916526 重新build element 210 widget: 318147042
flutter: StatefulColorfulTile 731559728 重新createState
flutter: ColorfulTileState 734210995 重新build element 214 widget: 731559728
可见element被多次创建
GlobalKey
不论两个Widget
是否是同一个父级,当Widget
交换位置的时候,Element
都会复用。
我们把上述代码做下简单修改:
List<Widget> tiles = [
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [StatefulColorfulTile(key: GlobalKey())],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [StatefulColorfulTile(key: GlobalKey())],
),
),
];
多次点击:
flutter: ColorfulTileState 11684886 重新build element 117 widget: 470363955
flutter: ColorfulTileState 11684886 重新build element 117 widget: 470363955
flutter: ColorfulTileState 291476133 重新build element 111 widget: 1022701588
flutter: ColorfulTileState 11684886 重新build element 117 widget: 470363955
flutter: ColorfulTileState 291476133 重新build element 111 widget: 1022701588
flutter: ColorfulTileState 291476133 重新build element 111 widget: 1022701588
flutter: ColorfulTileState 11684886 重新build element 117 widget: 470363955
可见element 没有创建新的,而是移动的了位置