InheritedWidget是Flutter中非常重要的一个功能型组件,它提供了一种数据在widget树中从上到下传递、共享的方式,比如我们在应用的根widget中通过InheritedWidget共享了一个数据,那么我们便可以在任意子widget中来获取该共享的数据!这个特性在一些需要在widget树中共享数据的场景中非常方便!如Flutter SDK中正是通过InheritedWidget来共享应用主题(Theme)和Locale (当前语言环境)信息的
didChangeDependencies
在之前介绍StatefulWidget时,我们提到State对象有一个didChangeDependencies回调,它会在“依赖”发生变化时被Flutter Framework调用。而这个“依赖”指的就是子widget是否使用了父widget中InheritedWidget的数据!如果使用了,则代表子widget依赖有依赖InheritedWidget;如果没有使用则代表没有依赖。这种机制可以使子组件在所依赖的InheritedWidget变化时来更新自身!比如当主题、locale(语言)等发生变化时,依赖其的子widget的didChangeDependencies方法将会被调用
如果子widget没有使用了父widget中InheritedWidget的数据!那么不会调用 didChangeDependencies
其实,这个机制很好理解,因为在数据发生变化时只对使用该数据的Widget更新是合理并且性能友好的
上代码:
main
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ShareDataWidget(
content: _counter,
child: ShareChildWidget(),
),
// Text(
// '$_counter',
// style: Theme.of(context).textTheme.display1,
// ),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
父widget
class ShareDataWidget extends InheritedWidget{
//共享的数据
final int content ;
ShareDataWidget({this.content,Widget child}) : super(child:child);
// 该回调决定data发生变化时,是否通知子树中依赖data的widget
@override
bool updateShouldNotify(ShareDataWidget oldWidget) {
// TODO: implement updateShouldNotify
return oldWidget.content != content;
}
/*
定义一个方法,方便子树中的widget获取这个widget,进而获得共享数据
* */
static ShareDataWidget of(BuildContext context){
/**
* 获取最近的给定类型的Widget,该widget必须是InheritedWidget的子类,
* 并向该widget注册传入的context,当该widget改变时,
* 这个context会重新构建以便从该widget获得新的值。
* 这就是child向InheritedWidget注册的方法。
*/
return context.inheritFromWidgetOfExactType(ShareDataWidget);
}
}
子widget
class ShareChildWidget extends StatefulWidget {
@override
_ShareChildWidgetState createState() => _ShareChildWidgetState();
}
class _ShareChildWidgetState extends State<ShareChildWidget> {
@override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(ShareDataWidget.of(context).content.toString()),
//child: Text("123"),
),
);
}
/*
父或祖先widget中InheritedWidget改变(updateShouldNotify 返回true)时
会被调用
如果build 中没有依赖 InheritedWidget ,则此回调不会被调用
* 如果依赖的InheritedWidget改变了,framework将会调用这个方法来通知这个对象。
* 在这个方法中调用BuildContext.inheritFromWidgetOfExactType是安全的。
* 子类很少覆写这个方法,因为framework通常会在依赖的InheritedWidget改变后调用build方法, * 覆写这个方法通常用来做一些耗时的工作,比如网络请求
*/
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
print("didChangeDependencies:");
}
}
应该在didChangeDependencies()中做什么?
一般来说,子widget很少会重写此方法,因为在依赖改变后framework也都会调用build()方法。但是,如果你需要在依赖改变后执行一些昂贵的操作,比如网络请求,这时最好的方式就是在此方法中执行,这样可以避免每次build()都执行这些昂贵操作