使用🌰
- ShareDataWidget继承inheritedWidget,创建共享数据.提供便捷方法,使子树中的widget获取共享数据.
class ShareDataWidget extends InheritedWidget {
ShareDataWidget({@required this.data, Widget child}) : super(child: child);
final int data; //需要在子树中共享的数据,保存点击次数
//定义一个便捷方法,方便子树中的widget获取共享数据
static ShareDataWidget of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType(); //该方法沿着Element树,去找最近的CounterElement , 然后从Element中取出的Widget对象
}
//该回调决定当data发生变化时,是否通知子树中依赖data的Widget(子widget didChangeDependencies方法有没有走)
@override
bool updateShouldNotify(ShareDataWidget old) {
//如果返回true,则子树中依赖(build函数中有调用)本widget
//的子widget的`state.didChangeDependencies`会被调用
return old.data != data;
}
}
2.创建子Widget,依赖InheritedWidget的数据.(这里创建两个Widget,一个StatefulWidget,一个StatelessWidget)
class TestInheritedWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return __TestWidgetState();
}
}
class __TestWidgetState extends State<TestInheritedWidget> {
@override
Widget build(BuildContext context) {
print("Test1InheritedWidget---build");
//使用InheritedWidget中的共享数据
return Text("StatefulWidget=====" +
ShareDataWidget.of(context).data.toString()); //显示data
}
///子树收到改变通知s
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
print("执行didChangeDependencies");
}
}
class Test2InheritedWidget extends StatelessWidget {
const Test2InheritedWidget({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
print("Test2InheritedWidget---build");
return Text("StatelessWidget=====" +
ShareDataWidget.of(context).data.toString()); //显示data
}
}
3.test页面,使用ShareDataWidget展示共享数据.数据变化时,依然需要执行setState,更新ShareDataWidget
class InheritedWidgetTestPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _InheritedWidgetTestPageState();
}
}
class _InheritedWidgetTestPageState extends State<InheritedWidgetTestPage> {
int count = 5;
@override
Widget build(BuildContext context) {
print("_InheritedWidgetTestPageState---build");
return Scaffold(
appBar: AppBar(
title: Text("inheritedWidget"),
),
body: Center(
child: Column(
children: [
_inheritedWidget(),
ElevatedButton(
child: Text("+"),
//每点击一次,将count+1,然后重新build,ShareDataWidget的data将被更新
onPressed: () => setState(() => ++count),
),
ElevatedButton(
child: Text("-"),
//每点击一次,将count-1,然后重新build,ShareDataWidget的data将被更新
onPressed: () => setState(() => --count),
),
],
),
),
floatingActionButton: FloatingActionButton(
heroTag: "tosecond_tag",
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => InheritedWidgetTest2Page())),
child: Icon(Icons.navigate_next),
),
);
}
Widget _inheritedWidget() {
return ShareDataWidget(
//使用ShareDataWidget
data: count,
child: _childWidget(),
);
}
Widget _childWidget() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 100.0),
child: TestInheritedWidget(), //子widget中依赖ShareDataWidget
),
Padding(
padding: const EdgeInsets.only(bottom: 150.0),
child: Test2InheritedWidget(), //子widget中依赖ShareDataWidget
),
],
);
}
}
class InheritedWidgetTest2Page extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _InheritedWidgetTest2PageState();
}
}
class _InheritedWidgetTest2PageState extends State<InheritedWidgetTest2Page> {
int count = 0;
@override
Widget build(BuildContext context) {
print("_InheritedWidgetTest2PageState---build");
return Scaffold(
appBar: AppBar(
title: Text("inheritedWidget"),
),
body: Center(
child: Column(
children: [
_inheritedWidget(),
ElevatedButton(
child: Text("+"),
//每点击一次,将count+1,然后重新build,ShareDataWidget的data将被更新
onPressed: () => setState(() => ++count),
),
ElevatedButton(
child: Text("-"),
//每点击一次,将count-1,然后重新build,ShareDataWidget的data将被更新
onPressed: () => setState(() => --count),
),
],
),
));
}
Widget _inheritedWidget() {
return ShareDataWidget(
//使用ShareDataWidget
data: count,
child: _childWidget(),
);
}
Widget _childWidget() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 100.0),
child: TestInheritedWidget(), //子widget中依赖ShareDataWidget
),
Padding(
padding: const EdgeInsets.only(bottom: 150.0),
child: Test2InheritedWidget(), //子widget中依赖ShareDataWidget
),
],
);
}
}
总结
通过例子,我们可以看出
1.依赖共享数据的StatefulWidget(TestInheritedWidget),在数据更新时,会执行didChangeDependencies方法.另外,是否会执行didChangeDependencies方法取决于inheritedWidget(ShareDataWidget)内部updateShouldNotify返回的布尔值以及TestInheritedWidget是否依赖了这个共享数据.
2.依赖共享数据,即在widget中使用了inheritedWidget提供的便捷方法获取数据.
-
3.如果我们只想在__TestWidgetState中引用ShareDataWidget数据,但却不希望在ShareDataWidget发生变化时调用__TestWidgetState的didChangeDependencies()方法应该怎么办?
image.png
唯一的改动就是获取ShareDataWidget对象的方式,把dependOnInheritedWidgetOfExactType()方法换成了context.getElementForInheritedWidgetOfExactType<ShareDataWidget>().widget,看一下这两个方法的源码:
image.png
image.png
image.png
可以看到dependOnInheritedElement方法中主要是注册了依赖关系!看到这里也就清晰了,调用dependOnInheritedWidgetOfExactType() 和 getElementForInheritedWidgetOfExactType()的区别就是前者会注册依赖关系,而后者不会,所以在调用dependOnInheritedWidgetOfExactType()时,InheritedWidget和依赖它的子孙组件关系便完成了注册,之后当InheritedWidget发生变化时,就会更新依赖它的子孙组件,也就是会调这些子孙组件的didChangeDependencies()方法和build()方法。而当调用的是 getElementForInheritedWidgetOfExactType()时,由于没有注册依赖关系,所以之后当InheritedWidget发生变化时,就不会更新相应的子孙Widget。
4.context
.dependOnInheritedWidgetOfExactType(); //该方法沿着Element树,去找最近的Element , 然后从Element中取出的Widget对象 , 该widget必须是InheritedWidget的子类,并向上级widget注册传入的context,当上级widget改变时,这个context持有的widget会rebuild以便从该widget获得新的值。这就是child向InheritedWidget注册的方法。5.inheritedWidget(ShareDataWidget)共享数据是只读的,如果要实现数据变化更新,依然需要依赖于StatefulWidget(InheritedWidgetTestPage)的setState.
6.不支持跨页面的状态.
如果我在A页面使用InheritedWidget储存了数据,跳转到B页面或者C页面,会发现使用context获取不到A页面的InheritedElement(A页面跳转B页面,B页面并不是A页面的子节点)
补充:
如共享对象为一个Bean类, 仅仅改变Bean类中的某个属性,updateShouldNotify返回为false,是不会触发didChangeDependencies方法的
参考
https://book.flutterchina.club/chapter7/inherited_widget.html