什么是Widget
Flutter中几乎所有的对象都是一个Widget,这与原生开发中“控件”概念稍有不同,Flutter中的Widget表示一切与UI框架相关的对象,例如:手势检测 GestureDetector,而原生开发中的Widget控件通常仅仅指UI布局中的各种控件,不包含Flutter中的功能型Widget。
标识符:Key
Flutter 是响应式框架,每次刷新 UI 的时候,都会重新构建新的 Widget树,并和之前的 Widget树进行对比,计算出变化的部分,这个计算过程就是diff,在 diff 过程中,如果能提前知道哪些 Widget 没有变化,就能提高 diff 的性能,这时候就需要使用到标识符。
给 Widget 添加一个唯一的标识符,然后在 Widget树 的 diff 过程中查看刷新前后的 Widget树,如果标识符相同,则说明 Widget 没有变化,否则说明 Widget 有变化。
这个标识符就是Flutter 中的Key属性,所有 Widget 都有 Key 属性
Key有两种类型:
- Local Key(局部Key)
- Global Key(全局Key)
什么是StatelessWidget
它是一个比较简并继承自Widget类的一个类,常在build方法中通过嵌套其它Widget来构建UI。当我们需要组合并封装多个Widget控件,且不需要维护数据状态时,可以自定义Widget并继承该类。它最大的特点是仅表示当前一帧的页面,当页面动态变化时,每次都会重建数据。
需要注意,它的内部成员变量是immutable的,通常需要使用final修饰。
什么是 StatefulWidget
它也是继承自Widget类,不同的是一个StatefulWidget类就会对应一个State类。State表示与其对应的StatefulWidget要维护的状态,且State中存在与原生开发中类似的生命周期回调。
State 类有两个功能:
- build() 方法创建 UI
- setState() 方法刷新 UI
调用setState()方法并在其中修改数据的值,会触发 State 的 build() 方法,重建 Widget,重建时会重新绑定数据,这时数据已变化,从而达到更新页面的目的。
State 中还有三个重要的成员变量
- widget 通过该变量可访问 StatefulWidget 中定义的成员属性
- context 用于获取当前 StatefulWidget 中的上下文
- mounted 判断当前 State 是否已加载到树中。在State 对象创建之后,initState() 调用之前,框架会将 State 对象加载到树中,此时 mounted 会变为 true,当 State dispose 之后,mounted 就为 false。因此,在setState() 调用前可判断 mounted 的值以避免异常,mounted 为 false 时调用setState()会报错。
if(mounted){
setState((){
// :TODO
})
}
StatelessWidget 和 StatefulWidget的区别
- StatelessWidget 是 UI 不可变化的 Widget,创建完后 UI 就不能发生变化;
- StatefulWidget 是 UI 可变化的 Widget,并存在生命周期,创建完后 UI 可以更改。通常的,一个单独页面的根Widget应当使用StatefulWidget 包裹,存在并需要封装动画时,也需要使用StatefulWidget封装控件。
widget生命周期回调
StatefulWidget 生命周期回调
- initState 当Widget 第一次插入到 Widget树时被调用,对于每一个State对象,该回调只会调用一次,所以通常会在回调中做一些初始化。覆写此方法时,应在调用super.iniState()之后
- didChangeDependencies 创建时在initState 之后被调用,或者当State对象的依赖发生变化时调用,子类很少覆写
- build 构建该Widget 表示的UI元素。此方法在不同情况下被调用:
1.调用initState之后
2.调用didUpdateWidget之后
3.调用setState之后
4.当State对象的依赖更改(didChangeDependencies)之后
5.当State对象从树中一个位置移除后(调用deactivate)又重新插入到树的其它位置时调用 - didUpdateWidget 当Widget 的状态发生改变时调用,例如调用setState
- deactivate 当State对象从树中被移除时,会调用此回调。如果移除后没有重新插入到树中则紧接着会调用dispose方法,如果覆写此方法,应在调用super.deactivate()之前
dispose 当State对象从树中被永久移除时调用。通常在此回调中释放资源,如果覆写此方法,应在调用super.dispose()之前
class _MyHomePageState extends State<MyHomePage> {
//定义变量区域
final GlobalKey _gk = GlobalKey();
int count = 0;
//定义其他函数,放前面或者后面都可以
void _showHint() {
}
//widget生命周期函数如下
@override
void initState() {
// TODO: implement initState
super.initState();
debugPrint('initState');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
debugPrint('didChangeDependencies');
}
@override
Widget build(BuildContext ctx) {
// this.context;
return Scaffold();
}
@override
void didUpdateWidget(covariant MyHomePage oldWidget) {
super.didUpdateWidget(oldWidget);
debugPrint('didUpdateWidget');
}
@override
void deactivate() {
super.deactivate();
debugPrint('deactivate');
}
@override
void dispose() {
super.dispose();
debugPrint('dispose');
}
}
App 的生命周期
除了Widget,App本身也存在生命周期,这类似原生App的生命周期,主要指进入app,按home键等系统级的操作。
要监听系统级的App生命周期回调,需要在页面的State类上混入WidgetsBindingObserver类,并实现didChangeAppLifecycleState回调方法
注意:不要忘了注册和移除监听器,否则不生效
class _MyAppState extends State<MyApp> with WidgetsBindingObserver{
@override
void initState() {
super.initState();
/// 注册监听器
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
break;
case AppLifecycleState.inactive:
break;
case AppLifecycleState.paused:
break;
case AppLifecycleState.detached:
break;
}
}
@override
void dispose() {
/// 移除监听器
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
AppLifecycleState提供四种状态
- resumed 应用处于前台,可见可交互
- inactive应用处于非活动状态。在 iOS 上,当在通话、响应TouchID请求、进入应用切换器或控制中心时,应用会过渡到这个状态。在Android上,当其他活动被聚焦时,例如分屏应用、电话呼叫、画中画应用、弹出系统对话框时,应用会过渡到这个状态
- paused应用不可见,处于后台运行时处于该状态
- detached Flutter引擎第一次初始化时正在加载视图,或在视图因Navigator.pop 而被摧毁后时,处于该状态
网友评论