InheritedWidget是一个特殊的widget,可以存储和获取数据,子组件可以获取到存储的数据,常用的 MediaQuery、Theme 就是继承了 InheritedWidget
inherited widget 定义
- 数据传递和数据共享
实现数据分发:在不同的widget中获得共同的数据
- 对其他Widget的一个实现或者补充
- 例如:
Theme.of(context)
返回你能拿到一个ThemeData - 并使用其内部自定义的属性改变你当前widget的显示效果
相信大家很熟悉这段代码 MediaQuery.of(context).size.width;
class MediaQuery extends InheritedWidget {
const MediaQuery({
Key key,
@required this.data,
@required Widget child,
}) : assert(child != null),
assert(data != null),
super(key: key, child: child);
///...
final MediaQueryData data;
///...
static MediaQueryData of(BuildContext context, { bool nullOk = false }) {
///...
}
}
直接上案例:如何在不同的widget中获得共同的数据

购物车商品数量添加和减少
1.创建一个Item模型,用于保存购物车的数量
class Item {
String reference;
Item(this.reference);
}
2.创建一个InheritedWidget
class _MyInherited extends InheritedWidget {
_MyInherited({
Key key,
@required Widget child,
@required this.data,
}) : super(key: key, child: child);
final MyInheritedWidgetState data;
@override
bool updateShouldNotify(_MyInherited oldWidget) {
return true;
}
}
class MyInheritedWidget extends StatefulWidget {
MyInheritedWidget({
Key key,
this.child,
}) : super(key: key);
final Widget child;
@override
MyInheritedWidgetState createState() => new MyInheritedWidgetState();
static MyInheritedWidgetState of(
[BuildContext context, bool rebuild = true]) {
return (rebuild
? context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited
: context.ancestorWidgetOfExactType(_MyInherited) as _MyInherited)
.data;
}
}
3.创建一个MyInheritedWidgetState 来管理全局状态
class MyInheritedWidgetState extends State<MyInheritedWidget> {
List<Item> _items = <Item>[];
int get itemsCount => _items.length;
//添加Item
void addItem(String reference) {
setState(() {
_items.add(new Item(reference));
});
}
//移除Item
void removeItem() {
setState(() {
if (_items.length > 0){
_items.removeLast();
}
});
}
@override
Widget build(BuildContext context) {
return new _MyInherited(
data: this,
child: widget.child,
);
}
}
4.组合使用
关键代码
// 防止WidgetA被rebuild
final MyInheritedWidgetState state = MyInheritedWidget.of(context, false);
class MyTree extends StatefulWidget {
@override
_MyTreeState createState() => new _MyTreeState();
}
class _MyTreeState extends State<MyTree> {
@override
Widget build(BuildContext context) {
return MyInheritedWidget(
child: new Scaffold(
appBar: new AppBar(
title: new Text('Title'),
),
body: new Column(
children: <Widget>[
new WidgetA(),
new WidgetD(),
new Container(
child: new Row(
children: <Widget>[
new Icon(Icons.shopping_cart),
new WidgetB(),
new WidgetC(),
],
),
),
],
),
),
);
}
}
class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyInheritedWidgetState state = MyInheritedWidget.of(context, false); // 防止WidgetA被rebuild
return new Container(
child: new RaisedButton(
child: new Text('Add Item'),
onPressed: () {
state.addItem('new item');
},
),
);
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
return new Text('${state.itemsCount}');
}
}
class WidgetC extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Text('I am Widget C');
}
}
class WidgetD extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyInheritedWidgetState state = MyInheritedWidget.of(context, false); // 防止WidgetA被rebuild
return new Container(
child: new RaisedButton(
child: new Text('Remove Item'),
onPressed: () {
state.removeItem();
},
),
);
}
}
补充
1.inheritFromWidgetOfExactType
-
获取最近的给定类型的Widget
,该widget必须是InheritedWidget的子类,并向该widget注册传入的context,当该widget改变时,这个context会重新构建以便从该widget获得新的值。这就是child向InheritedWidget注册的方法。 继承的 widget 将在更改时触发重新构建
2.ancestorWidgetOfExactType
- 适用于交互事件处理程序(例如手势回调)或执行一次性任务,例如 断言 您拥有或不具有作为特定类型的父 widget 。 widget 的构建方法的返回值不应该依赖于该方法返回的值,因为
如果该方法的返回值发生更改,构建上下文将 不会重新生成
。这可能会导致生成方法中使用的数据发生更改,但是没有重新生成 widget 。 - 可以用来获取父 widget 的一些信息
网友评论