Flutter中的widget
的刷新主要是靠State
来控制,在对应的逻辑中setState()
便可达到刷新widget的效果。
在flutter中,常用的widget有两种:
- StatelessWidget:无状态不需要刷新
- StatefulWidget:有状态需要通过
setState()
更新
1.StatelessWidget:
一些创建之后就不会在根据数据或者逻辑再去变更页面的样式的widget,比如:固定的Image、一些不会更改的文本描述等。例如下面的例子:
class TitleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(context);
}
StatelessWidget的生命周期只有build()
一个函数,在build()
中返回对应的视图就可以了。
2.StatefulWidget:
根据状态可以进行UI的变更,变更的逻辑是通过修改参数进行UI的变更,且需要在setState(){}
包裹
setState((){
// 更新状态、数据
})
创建一个动态的widget:
class DynamicWidget extends StatefulWidget {
DynamicWidget({Key key}) : super(key: key);
@override
_DynamicWidgetState createState() => _DynamicWidgetState();
}
class _DynamicWidgetState extends State {
@override
Widget build(BuildContext context) {
return Container();
}
}
创建Widget,重写createState()
函数,然后实例State
,在State
中实现UI和具体的交互。
2.1 Stateful的生命周期:
Widget的生命周期如上图所示,包含了 初始化、 状态改变、 销毁 三个阶段。
createState()
widget中重写createState()
创建State
实例.
initState()
界面创建之前调用的函数,完成一些需要在UI之前的操作,比如参数赋值之类。
didChangeDependencies()
initState()
完成之后会调用改函数。
build()
构建UI,返回一个widget,整个页面的创建在此完成。deactivate()
当State
被暂时从视图移除的时候会调用,页面push
走、pop
回来的时候都会调用。
因为push、pop
会改变widget在视图树位置,需要先移除再添加。
必须要先调用super.deactivate()
dispose()
页面被销毁的时候调用,如:pop
操作。
必须先调用父类super.dispose()
,通常情况下,自己的释放逻辑放在super.dispose()
之前,先操作子类在操作父类。setState()
每当我们手动调用这个函数是,会触发build()
重新构建UI。
代码如下:
class _DynamicWidgetState extends State {
@override
void initState() {
super.initState();
print('------------initState');
}
@override
Widget build(BuildContext context) {
print('------build');
return Container();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('------------didChangeDependencies');
}
@override
void deactivate() {
super.deactivate();
print('------------deactivate');
}
@override
void dispose() {
super.dispose();
print('------------dispose');
}
}
调用的结果:
红色为push
进来的调用顺序,蓝色为pop
走的调用顺序,beforePage
是前一个界面的push走,和pop回来都调用了deactivate
函数。
3.状态回调
在上述函数中基本上能完成相关逻辑开发,但是有时候并不能完全满足需求,比如:需要知道build()
完成的时机,需要知道后台挂机和返回等。
-
addPostFrameCallback
该回调会在widget渲染完成之后回调,只会调用一次,setState()
刷新UI,也不会在调用。
这里我们改造一下initState()
@override
void initState() {
super.initState();
print('------------initState');
WidgetsBinding.instance.addPostFrameCallback(_buildAfter);
}
void _buildAfter(_) {
print('------------_buildAfter');
}
_buildAfter()
函数会在build()
调用之后紧接着调用,在这个函数里,我们可以做一些相关的逻辑,比如:查看其中wiget的size
和offset
等操作。
4.前后台监听
前后台的监听其实已经不是widget的生命周期了,应该属于App级别的生命周期,这里需要用到WidgetsBindingObserver
- 修改State实例,mix
WidgetsBindingObserver
class _DynamicWidgetState extends State with WidgetsBindingObserver {}
- 在此修改
initState()
加入监听:
@override
void initState() {
super.initState();
print('------------initState');
WidgetsBinding.instance.addPostFrameCallback(_buildAfter);
WidgetsBinding.instance.addObserver(this);
}
- 在
disposr()
中移除监听,添加、移除监听和别的语言一样,需要一一对应,否则就会出现内存问题
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
print('------------dispose');
}
- 重写
didChangeAppLifecycleState
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print('------------$state--------');
}
AppLifecycleState
具体的值有:
resumed
inactive
paused
suspending
按需在对应的状态写对应的逻辑就好了。
总结
自此widget的生命周期和App的生命周期都已经说完了,水平有限,哪里写错了,一定要告诉我哈~~