InheritedWidget是Flutter的一个功能型的Widget基类,它能有效地将数据在当前Widget树中向它的子widget树传递。
它的子Widget树可以通过 BuildContext.inheritedFromWidgetOfExactType()方法获得最近的指定类型的Inherited widget,进而获取它的共享数据。
在介绍State生命周期时,我们说到State对象有一个didChangeDependencies方法,他会在“依赖”发生改变时framework调用。
而这里的“依赖”指的就是“是否使用了父Widget中InheritedWidget的数据”,如果使用了,就代表有依赖,如果没有使用,则代表没有依赖。这种依赖也被用于主题的变化等,随着主题的变化,子Widget做出相应的变化。
接下来我们通过一个例子来使用InheritedWidget!
首先我们通过继承InheritedWidget,将数据data保存在ShareWidget中。
class ShareWidget extends InheritedWidget{
int data;
ShareWidget({@required this.data,Widget child}) : super(child: child);
//定义一个方法,方便子树中的widget获取这个widget,进而获得共享数据。
static ShareWidget of(BuildContext context){
/**
* 获取最近的给定类型的Widget,该widget必须是InheritedWidget的子类,
* 并向该widget注册传入的context,当该widget改变时,
* 这个context会重新构建以便从该widget获得新的值。
* 这就是child向InheritedWidget注册的方法。
*/
return context.inheritFromWidgetOfExactType(ShareWidget);
}
/**
* framework通过使用以前占据树中的这个位置的小部件作为参数调用这个函数来区分这些情况。
*/
@override
bool updateShouldNotify(ShareWidget oldWidget) {
return oldWidget.data != data;
}
}
可以看到,定义了一个构造方法,传入data参数。然后定义一个静态方法 of(context),以便子widget获取该widget,进而获得共享的数据。在of(context)方法中,
context.inheritFromWidgetOfExactType(ShareWidget)
这个方法的作用:获取最近的给定类型(这里的类型是ShareWidget)的Widget,该widget必须是InheritedWidget的子类,并向该widget注册传入的context,当该widget改变时,这个context会重新构建以便从该widget获得新的值。这就是child向InheritedWidget注册的方法。
比如我们可以在子widget A中调用该方法,获得离A最近的继承了InheritedWidget的widget,获得该widget中的数据。下面会演示
接下来我们定义一个_TextWidget,在它的State的build方法中依赖ShareWidget中的data。
class _TextWidget extends StatefulWidget{
@override
State createState() {
return _TextWidgetState();
}
}
class _TextWidgetState extends State<_TextWidget>{
@override
Widget build(BuildContext context) {
return Text(
ShareWidget.of(context).data.toString()
);
}
/**
* 如果依赖的InheritedWidget改变了,framework将会调用这个方法来通知这个对象。
* 在这个方法中调用BuildContext.inheritFromWidgetOfExactType是安全的。
* 子类很少覆写这个方法,因为framework通常会在依赖的InheritedWidget改变后调用build方法,
* 覆写这个方法通常用来做一些耗时的工作,比如网络请求
*/
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("Dependencies change");
}
}
在build方法中,我们调用ShareWidget.of(context)方法获得最近的继承了InheritedWidget并且是ShareWidget类型的widget,
获取其data数据。
didChangeDependencies方法:
如果依赖的InheritedWidget改变了,framework将会调用这个方法来通知这个对象。在这个方法中调用BuildContext.inheritFromWidgetOfExactType是安全的。子类很少覆写这个方法,因为framework通常会在依赖的InheritedWidget改变后调用build方法,覆写这个方法通常用来做一些耗时的工作,比如网络请求。
接着就是在页面中使用这个_TextWidget了。
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ShareWidget( //使用ShareWidget
data: _counter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Text('You have clicked the button this many time:'),
),
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: _TextWidget(), //子widget中依赖ShareWidget
),
RaisedButton(
child: Text('Increment'),
onPressed: () => setState(()=> ++_counter),
),
],
),
),
),
);
}
}
build中使用了ShareWidget,并将_TextWidget作为ShareWidget的子Widget,这样就能成功依赖了。
这里我直接贴完整代码和演示效果:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class InheritedTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Home :'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ShareWidget( //使用ShareWidget
data: _counter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Text('You have clicked the button this many time:'),
),
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: _TextWidget(), //子widget中依赖ShareWidget
),
RaisedButton(
child: Text('Increment'),
onPressed: () => setState(()=> ++_counter),
),
],
),
),
),
);
}
}
class ShareWidget extends InheritedWidget{
int data;
ShareWidget({@required this.data,Widget child}) : super(child: child);
//定义一个方法,方便子树中的widget获取这个widget,进而获得共享数据。
static ShareWidget of(BuildContext context){
/**
* 获取最近的给定类型的Widget,该widget必须是InheritedWidget的子类,
* 并向该widget注册传入的context,当该widget改变时,
* 这个context会重新构建以便从该widget获得新的值。
* 这就是child向InheritedWidget注册的方法。
*/
return context.inheritFromWidgetOfExactType(ShareWidget);
}
/**
* framework通过使用以前占据树中的这个位置的小部件作为参数调用这个函数来区分这些情况。
*/
@override
bool updateShouldNotify(ShareWidget oldWidget) {
return oldWidget.data != data;
}
}
class _TextWidget extends StatefulWidget{
@override
State createState() {
return _TextWidgetState();
}
}
class _TextWidgetState extends State<_TextWidget>{
@override
Widget build(BuildContext context) {
return Text(
ShareWidget.of(context).data.toString()
);
}
/**
* 如果依赖的InheritedWidget改变了,framework将会调用这个方法来通知这个对象。
* 在这个方法中调用BuildContext.inheritFromWidgetOfExactType是安全的。
* 子类很少覆写这个方法,因为framework通常会在依赖的InheritedWidget改变后调用build方法,
* 覆写这个方法通常用来做一些耗时的工作,比如网络请求
*/
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("Dependencies change");
}
}
InheritedWidget 就介绍到这里。喜欢的点个赞~~