在Theme.of(context)、 MediaQuery.of(context)等实现代码都能看到InheritedWidget的身影:
InheritedWidget是Flutter中非常重要的一个功能型组件,它提供了一种数据在widget树中从上到下传递、共享的方式,比如我们在应用的根widget中通过InheritedWidget共享了一个数据,那么我们便可以在任意子widget中来获取该共享的数据!这个特性在一些需要在widget树中共享数据的场景中非常方便!
1、首先继承InheritedWidget,并实现自定义of静态方法和重写updateShouldNotify方法,如下:
数据共享InheritedWidget/*
*
说明:
state.didChangeDependencies
会被调用;返回false,则不会调用;2、子widget使用自定义InheritedWidget的共享数据或方法,如下:
class DependenceWidgetA extends StatefulWidget {
@override
_DependenceWidgetAState createState() => new _DependenceWidgetAState();
}
class _DependenceWidgetAState extends State {
@override
Widget build(BuildContext context) {
//使用InheritedWidget中的共享数据
final shareDataInheritedWidget = ShareDataInheritedWidget.of(context);
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Text(
'DependenceWidgetA : ${shareDataInheritedWidget?.showInfo() ?? 'null'}',textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
print("DependenceWidgetA didChangeDependencies");
}
}
说明:
3、InheritedWidget状态变化通知子widget,如下:
class DependenceWidgetA extends StatefulWidget {
@override
_DependenceWidgetAState createState() => new _DependenceWidgetAState();
}
class _DependenceWidgetAState extends State {
@override
Widget build(BuildContext context) {
//使用InheritedWidget中的共享数据
final shareDataInheritedWidget = ShareDataInheritedWidget.of(context);
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Text(
'DependenceWidgetA : ${shareDataInheritedWidget?.showInfo() ?? 'null'}',textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
print("DependenceWidgetA didChangeDependencies");
}
}
说明:
自定义InheritedWidget->ShareDataInheritedWidget,用于共享数据和方法,如下:
class ShareDataInheritedWidget extends InheritedWidget {
final String name; //用于区分子widget调用的是哪个ShareDataInheritedWidget
//共享数据
final InheritedShareModel shareModel;
//点击+号的方法
final Function() increment;
//点击-号的方法
final Function() reduce;
ShareDataInheritedWidget(
this.name, {
Key key,
@required this.shareModel,
@required this.increment,
@required this.reduce,
@required Widget child,
}) : super(key: key, child: child);
///定义一个便捷方法,方便子树中的widget获取共享数据--InheritedWidget变化时会通知子widget的didChangeDependencies
static ShareDataInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
///定义一个便捷方法,方便子树中的widget获取共享数据--InheritedWidget变化时不会通知子widget的didChangeDependencies
static ShareDataInheritedWidget ofNotNoticeDependence(BuildContext context) {
return context
.getElementForInheritedWidgetOfExactType()
?.widget;
}
///该回调决定当data发生变化时,是否通知子树中依赖data的Widget
@override
bool updateShouldNotify(ShareDataInheritedWidget oldWidget) {
//如果返回true,则子树中依赖(build函数中有调用)本widget
//的子widget的`state.didChangeDependencies`会被调用
return (null != shareModel?.count &&
null != oldWidget?.shareModel?.count &&
shareModel.count != oldWidget.shareModel.count);
}
///用于展示信息
String showInfo() {
return '来自${name ?? ''} InheritedWidget:ncount值为${shareModel?.count ?? ''}';
}
}
class InheritedShareModel {
final int count;
const InheritedShareModel(this.count);
}
说明:定义name共享变量主要是为了区别子widget访问到的共享数据来自哪个InheritedWidget
自定义InheritedWidget->TestInheritedWidget,用于理解InheritedWidget在树中的位置对子widget访问InheritedWidget的影响,如下:
class TestInheritedWidget extends InheritedWidget {
final String name; //用于区分子widget调用的是哪个TestInheritedWidget
TestInheritedWidget(
this.name, {
Key key,
@required Widget child,
}) : super(key: key, child: child);
static TestInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
///是否重建widget就取决于数据是否相同
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
///用于展示信息
String showInfo() {
return '来自${name ?? ''} TestInheritedWidget ';
}
}
各种widget访问自定义InheritedWidget里的共享数据和方法,如下:
class IncreaseWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final shareDataInheritedWidget = ShareDataInheritedWidget.of(context);
// print('IncreaseWidget : ${shareDataInheritedWidget?.showInfo()??'null'}');
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: RaisedButton(
textColor: Colors.black,
child: Text(
'+',
textAlign: TextAlign.center,
),
onPressed: shareDataInheritedWidget?.increment),
);
}
}
class DataWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final shareDataInheritedWidget = ShareDataInheritedWidget.of(context);
final inheritedShareModel = shareDataInheritedWidget?.shareModel;
// print('DataWidget : ${shareDataInheritedWidget?.showInfo() ?? ''}');
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Text(
'来自${shareDataInheritedWidget?.name ?? ''} InheritedWidget:ncount值为${inheritedShareModel?.count ?? ''}',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
);
}
}
class ReduceWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final shareDataInheritedWidget = ShareDataInheritedWidget.of(context);
// print('ReduceWidget : ${shareDataInheritedWidget?.showInfo() ?? ''}');
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: RaisedButton(
textColor: Colors.black,
child: Text('-', textAlign: TextAlign.center),
onPressed: shareDataInheritedWidget?.reduce),
);
}
}
class DependenceWidgetA extends StatefulWidget {
@override
_DependenceWidgetAState createState() => new _DependenceWidgetAState();
}
class _DependenceWidgetAState extends State {
@override
Widget build(BuildContext context) {
//使用InheritedWidget中的共享数据
final shareDataInheritedWidget = ShareDataInheritedWidget.of(context);
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Text(
'DependenceWidgetA : ${shareDataInheritedWidget?.showInfo() ?? 'null'}',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
print("DependenceWidgetA didChangeDependencies");
}
}
class DependenceWidgetB extends StatefulWidget {
@override
_DependenceWidgetBState createState() => new _DependenceWidgetBState();
}
class _DependenceWidgetBState extends State {
@override
Widget build(BuildContext context) {
//使用InheritedWidget中的共享数据
final shareDataInheritedWidget =
ShareDataInheritedWidget.ofNotNoticeDependence(context);
return Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Text(
'DependenceWidgetB : ${shareDataInheritedWidget?.showInfo() ?? 'null'}',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
//如果build中没有依赖InheritedWidget,则此回调不会被调用。
print("DependenceWidgetB didChangeDependencies");
}
}
在app层使用InheritedWidget,如下:
void main() => runApp(App());
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State {
InheritedShareModel _inheritedShareModel;
@override
void initState() {
super.initState();
_initData();
}
_initData() {
_inheritedShareModel = InheritedShareModel(0); //初始为0
}
_incrementCount() {
setState(() {
_inheritedShareModel =
InheritedShareModel(_inheritedShareModel.count + 2); //增幅度为2
});
}
_reduceCount() {
setState(() {
_inheritedShareModel =
InheritedShareModel(_inheritedShareModel.count - 2); //减幅度为2
});
}
@override
Widget build(BuildContext context) {
return ShareDataInheritedWidget(
'app层-在MaterialApp上',
shareModel: _inheritedShareModel,
increment: _incrementCount,
reduce: _reduceCount,
child: MaterialApp(
title: 'InheritedWidget使用示例',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TestInheritedWidget('app层-在MaterialApp里面', child: HomePage()),
),
/* child: TestInheritedWidget('app层-在MaterialApp上',child: MaterialApp(
title: 'InheritedWidget使用示例',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TestInheritedWidget('app层-在MaterialApp里面', child: HomePage()),
),),*/
);
}
}
在home页使用InheritedWidget,如下:
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
@override
Widget build(BuildContext context) {
return HomePageWidget();
}
@override
void deactivate() {
super.deactivate();
print('HomePage page deactivate');
}
@override
void dispose() {
super.dispose();
print('HomePage page dispose');
}
}
class HomePageWidget extends StatefulWidget {
@override
State createState() {
return _HomePageWidgetState();
}
}
class _HomePageWidgetState extends State {
CiteModel _testCiteModel;
InheritedShareModel _inheritedShareModel;
@override
void initState() {
super.initState();
_initData();
_testCiteModel = CiteModel(1);
}
@override
void deactivate() {
super.deactivate();
print('test page deactivate ${_testCiteModel ?? 'null'}');
}
_initData() {
_inheritedShareModel = InheritedShareModel(1); //初始化为1
}
_incrementCount() {
setState(() {
_inheritedShareModel =
InheritedShareModel(_inheritedShareModel.count + 1); //增幅度为1
});
}
_reduceCount() {
setState(() {
_inheritedShareModel =
InheritedShareModel(_inheritedShareModel.count - 1); //减幅度为1
});
}
@override
Widget build(BuildContext context) {
return ShareDataInheritedWidget('home',
shareModel: _inheritedShareModel,
increment: _incrementCount,
reduce: _reduceCount,
child: Scaffold(
appBar: AppBar(
title: Text('InheritedWidget使用示例'),
),
body: Container(
child: SingleChildScrollView(
child: Container(
/* width: double.infinity,
height: double.infinity,*/
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 20,
),
IncreaseWidget(),
DataWidget(),
ReduceWidget(),
DependenceWidgetA(),
DependenceWidgetB(),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("下一页"),
onPressed: () {
Navigator.push(
//跳转到第二个界面
context,
MaterialPageRoute(builder: (context) {
return NextPage();
}),
);
},
),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("home context"),
onPressed: () {
final ShareDataInheritedWidget
shareDataInheritedWidget =
ShareDataInheritedWidget.of(context); //home context
print(
'home context ShareDataInheritedWidget : ${shareDataInheritedWidget?.showInfo() ?? 'null'}');
final TestInheritedWidget testInheritedWidget =
TestInheritedWidget.of(context);
print(
'home context TestInheritedWidget: ${testInheritedWidget?.showInfo() ?? 'null'}');
},
),
SizedBox(
height: 20,
),
Builder(builder: (BuildContext context) {
//context变成home 子widget context
return RaisedButton(
child: Text("home 子widget context"),
onPressed: () {
final ShareDataInheritedWidget
shareDataInheritedWidget =
ShareDataInheritedWidget.of(
context); //home 子widget context
print(
'home 子widget context ShareDataInheritedWidget: ${shareDataInheritedWidget?.showInfo() ?? 'null'}');
final TestInheritedWidget testInheritedWidget =
TestInheritedWidget.of(context);
print(
'home 子widget context TestInheritedWidget: ${testInheritedWidget?.showInfo() ?? 'null'}');
},
);
}),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("测试type作为map key"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return TestTypePage();
}),
);
},
),
SizedBox(
height: 20,
),
RaisedButton(
child: Text("测试引用计数"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return TestModelCitePage(_testCiteModel);
}),
);
},
),
Padding(
padding: const EdgeInsets.only(
left: 10.0, top: 10.0, right: 10.0),
child: Text(
'Theme.of(context).textThemenMediaQuery.of(context).size等n就是通过InheritedWidget实现的',
style: TextStyle(fontSize: 20.0),
),
),
],
),
),
),
width: double.infinity,
height: double.infinity,
),
));
}
}
从home页用路由跳到下一页使用InheritedWidget,如下:
class NextPage extends StatefulWidget {
@override
_NextPageState createState() => _NextPageState();
}
class _NextPageState extends State {
@override
void initState() {
super.initState();
//直接在iniState使用InheritedWidget会报错
/*ShareDataInheritedWidget shareDataInheritedWidget =
ShareDataInheritedWidget.of(context);
print(
'next page initState shareDataInheritedWidget: ${shareDataInheritedWidget?.showInfo() ?? 'null'}');*/
Future.delayed(Duration.zero, () {
final ShareDataInheritedWidget shareDataInheritedWidget =
ShareDataInheritedWidget.of(context);
print(
'next page initState delayed shareDataInheritedWidget: ${shareDataInheritedWidget?.showInfo() ?? 'null'}');
});
}
@override
Widget build(BuildContext context) {
final TestInheritedWidget testInheritedWidget =
TestInheritedWidget.of(context);
print(
'next page build TestInheritedWidget: ${testInheritedWidget?.showInfo() ?? 'null'}');
final ShareDataInheritedWidget shareDataInheritedWidget =
ShareDataInheritedWidget.of(context);
print(
'next page build ShareDataInheritedWidget: ${shareDataInheritedWidget?.showInfo() ?? 'null'}');
return Scaffold(
appBar: AppBar(
title: Text('下一页'),
),
body: Container(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IncreaseWidget(),
DataWidget(),
ReduceWidget(),
],
),
),
);
}
}
操作如下:
示例说明:
详细信息请运行demo体验:InheritedWidget_Sample
从示例中可以得出以下结论:
InheritedWidget原理分析请移步:InheritedWidget内部实现原理浅析