Flutter中的4颗树 2023-09-05 周二
2023-09-04 本文已影响0人
勇往直前888
Widget
-
在
Flutter
中几乎所有的对象都是一个widget
。比如用于手势检测的GestureDetector
、用于APP主题数据传递的Theme
等等,都是widget
。 -
widget
的功能是“描述一个UI元素的配置信息”,非常轻量级,随时可以重绘。 -
Widget
是不可变的,Widget
中定义的属性(即配置信息)必须是不可变的(final)
-
Widget
类本身是一个抽象类,我们一般都不用直接继承Widget
类来实现一个新组件。 -
我们通常会通过继承
StatelessWidget
或StatefulWidget
来间接继承widget类。
4颗树
-
widget
是配置信息,会形成一颗widget
树,非常轻量级,不可变,随时会重绘。
-
- 根据
Widget
树生成一个Element
树,Element
树中的节点都继承自Element
类。这是一颗中间树,用于过渡。
- 根据
- 根据
Element
树生成Render
树(渲染树),渲染树中的节点都继承自RenderObject
类。这个负责具体的绘制,比较重量级。使用差量法,尽量减少重绘。
- 根据
- 根据渲染树生成
Layer
树,然后上屏显示,Layer
树中的节点都继承自Layer
类。这颗树跟GPU
有关,一般由Engine
层负责。
- 根据渲染树生成
三棵树中,
Widget
和Element
是一一对应的,但并不和RenderObject
一一对应。比如StatelessWidget
和StatefulWidget
都没有对应的RenderObject
StatefulWidget
- 能保留状态的原因是增加了一个
state
类。
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => StatefulElement(this);
@protected
State createState();
}
-
widget
,它表示与该State
实例关联的widget
实例,由Flutter
框架动态设置。注意,这种关联并非永久的,因为在应用生命周期中,UI
树上的某一个节点的widget
实例在重新构建时可能会变化,但State
实例只会在第一次插入到树中时被创建,当在重新构建时,如果widget
被修改了,Flutter
框架会动态设置State.widget
为新的widget
实例。
widget
经常变,但是State
一直是同一个,所以能保持状态。
-
State
生命周期
initState
只执行一次;build
经常执行; 对应的Widget
经常变;
通过Context获取State对象
-
一般会提供一个
of
方法对外暴露state
,这是一种约定俗成的习惯。 -
通过
state
可以实现动态界面。
Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
// 直接通过of静态方法来获取ScaffoldState
ScaffoldState _state=Scaffold.of(context);
// 打开抽屉菜单
_state.openDrawer();
},
child: Text('打开抽屉菜单2'),
);
}),
通过GlobalKey获取State对象
- 给目标
StatefulWidget
添加GlobalKey
。
//定义一个globalKey, 由于GlobalKey要保持全局唯一性,我们使用静态变量存储
static GlobalKey<ScaffoldState> _globalKey= GlobalKey();
...
Scaffold(
key: _globalKey , //设置key
...
)
- 通过
GlobalKey
来获取State
对象
_globalKey.currentState.openDrawer()
通过 RenderObject 自定义 Widget
-
Flutter
最原始的定义组件的方式就是通过定义RenderObject
来实现,而StatelessWidget
和StatefulWidget
只是提供的两个帮助类。
类似原生开发的画界面,就要通过
RenderObject
实现
-
用来继承的类分为三种:
LeafRenderObjectWidget,SingleChildRenderObjectWidget,MultiChildRenderObjectWidget
-
大概的样子
class CustomWidget extends LeafRenderObjectWidget{
@override
RenderObject createRenderObject(BuildContext context) {
// 创建 RenderObject
return RenderCustomObject();
}
@override
void updateRenderObject(BuildContext context, RenderCustomObject renderObject) {
// 更新 RenderObject
super.updateRenderObject(context, renderObject);
}
}
class RenderCustomObject extends RenderBox{
@override
void performLayout() {
// 实现布局逻辑
}
@override
void paint(PaintingContext context, Offset offset) {
// 实现绘制
}
}