InheritedWidget 使用
初识 Flutter 的 Demo 是一个点击按键然后数字增加的小应用,这小应用就涉及到了 Flutter 中的状态管理,核心就是 setState 方法。
setState 方法用于通知 Flutter 更新 Widget 的状态,比如重建当前 Widget 及其子树,它是从上到下进行通知的,但作用域仅停留在当前的 StatefulWidget 范围内。
如果有两个同级的 StatefulWidget ,比如 WidgetA 和 WidgetB ,当 WidgetA 的数据发生改变,想要通知 WidgetB 对应改变。
如果是 Android 的应用开发,采用 MVP 模式的话,需要 Controller 同时持有 WidgetA 和 WidgetB ,当 WidgetA 状态改变时,通过 Controller 对应改变 WidgetB 相关状态就行了。
原文地址:https://glumes.***/flutter-inheritedwidget-usage-and-analysis/
而在 Flutter 中基于 InheritedWidget 控件,通过相应的封装库就可以实现 MVVM 模式的开发,相当快捷方便。
通过如下的例子来学习 InheritedWidget 控件的使用:左边栏和右边栏是两个同级的 Widget ,右边栏中点击修改名称,左边栏中显示对应的修改内容。
因为 InheritedWidget 是从上到下进行数据共享、传递的,所以要把 InheritedWidget 作为根节点,需要共享数据的节点作为子节点。
通过继承 InheritedWidget 实现自定义的控件类:
class DataModelWidget extends InheritedWidget {
const DataModelWidget(
{
super.key,
required super.child,
required this.name,
required this.changeName});
// 当数据发生改变时,才会通知到子控件
bool updateShouldNotify(covariant DataModelWidget oldWidget) {
return oldWidget.name != name;
}
// 定义 static 快捷方法,方便在子控件中获取共享数据
// 当子控件通过 of 方法使用了 InheritedWidget 中的数据,注册依赖关系
// 此时数据变动会触发 didChangeDependencies 方法
static DataModelWidget? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<DataModelWidget>();
}
// 共享的数据
final String name;
final Function changeName;
}
要传递的数据就是 name 变量,在一个子控件中去修改 name 的值,在另一个子控件中显示修改内容。这里为了方便直接把要传递的数据放在了 Widget 里面,也可以封装对应的 Model 类,然后 Widget 持有 Model 类会更友好一些。
当数据发生改变时,会通过 updateShouldNotify 方法通知到子控件的 didChangeDependencies 方法。
didChangeDependencies 方法指的是子控件是否有依赖父 Widget 中 InheritedWidget 的数据,如果有就会响应回调。
子控件通过 of 静态方法获取 InheritedWidget 的时候调用了 dependOnInheritedWidgetOfExactType 方法,该方法会将 InheritedWidget 和获取数据的子控件进行注册,这才有了依赖关系。
child 参数就是接下来要写的子控件内容了。
class _DashboardState extends State<Dashboard> {
String _name = "glumes";
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Row(
children: <Widget>[
// 初始化 InheritedWidget 并传递对应参数
DataModelWidget(
name: _name,
changeName: _changeUserName,
child: const ContentBoard(),
)
],
),
),
),
);
}
// 右边栏调用 _changeUserName 方法修改共享数据的值
void _changeUserName(String userName) {
setState(() {
_name = userName;
});
}
}
把子控件封装在 ContentBoard 中,分别是:
// 左边栏
Text("名称:${
DataModelWidget.of(context)!.name}"),
void didChangeDependencies() {
super.didChangeDependencies();
Log.d("left sidebar change dependencies");
}
// 右边栏
ElevatedButton(
onPressed: () {
DataModelWidget.of(context)!.changeName("change name ${
count.toString()}");
count++;
},
child: <