问题描述
关于 InheritedWidget
有一些我不明白的困惑。
我在 stackoverflow 上搜索并阅读了一些关于 InheritedWidget
的 QA,但仍有一些我不明白的地方。
首先,让我们创建一个场景。
这是我的InheritedWidget
:
class MyInheritedWidget extends InheritedWidget {
final String name;
MyInheritedWidget({
@required this.name,@required Widget child,Key key,}) : super(key: key,child: child);
@override
bool updateShouldNotify(MyInheritedWidget oldWidget) =>
oldWidget.name != this.name;
static MyInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetofExactType<MyInheritedWidget>();
}
}
这是包含 MyHomePage
的 MyInheritedWidget
。 MyInheritedWidget
有两个子项:WidgetA
和一个导航到另一个屏幕的按钮,在本例中为 Page1
。
class MyHomePage extends StatefulWidget {
@override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),),body: Center(
child: MyInheritedWidget(
name: 'Name',child: Column(
children: [
WidgetA(),TextButton(
onpressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Page1(),);
},child: Text('Go to page 1'),)
],);
}
}
在 WidgetA
中,有一个文本小部件显示 MyInheritedWidget
中的 name 字段和另一个导航到 Page2
的按钮。
class WidgetA extends StatefulWidget {
@override
_WidgetAState createState() => _WidgetAState();
}
class _WidgetAState extends State<WidgetA> {
@override
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
return Column(
children: [
Text(myInheritedWidget.name),TextButton(
onpressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Page2(),);
},child: Text('Go to page 2'),)
],);
}
}
Page1
和 Page2
只有一个文本小部件,用于显示 MyInheritedWidget
中的 name 字段。
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Page 1'),body: Text(myInheritedWidget.name),);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Page 2'),);
}
}
在这种情况下,MyInheritedWidget
的 name 字段无法通过 Page1
和 Page2
访问,但可以在 WidgetA
中访问.
现在让我们来回答问题:
据说可以从其所有后代访问 InheritedWidget
。后代是什么意思?
在 MyHomePage
中,我知道 WidgetA
是 MyInheritedWidget
的后代。但是,Page1
也是 MyInheritedWidget
的后代吗?
如果答案是否定的,我怎样才能让 Page1
成为 MyInheritedWidget
的后代?
我是否需要再次将其包裹在 MyInheritedWidget
中?
如果有这样的导航链:Page1-> Page2 -> Page3 ... Page10并且我想访问 Page10 中的 MyInheritedWidget
,我是否必须将每个页面都包裹在 MyInheritedWidget
中?
解决方法
正如@pskink 所说,MyHomePage
推送 Page1
,它是 Navigator
的后代,它在 MaterialApp
之下,而不是 MyInheritedWidget
。最简单的解决方案是在 MyInheritedWidget
上方创建 MaterialApp
。这是我的代码(使用 ChangeNotifierProvider
而不是 MyInheritedWidget
)。
void main() {
setupLocator();
runApp(DevConnectorApp());
}
class DevConnectorApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final log = getLogger('DevConnectorApp');
return MultiProvider(
providers: [
ChangeNotifierProvider<AuthService>(
create: (ctx) => AuthService(),),ChangeNotifierProxyProvider<AuthService,ProfileService>(
create: (ctx) => ProfileService(),update: (ctx,authService,profileService) =>
profileService..updateAuth(authService),],child: Consumer<AuthService>(builder: (ctx,_) {
log.v('building MaterialApp with isAuth=${authService.isAuth}');
return MaterialApp(
以下示例使用多个 Navigators
来限定 InheritedWidget
。小部件 ContextWidget
创建一个 InheritedWidget
和一个 Navigator
,并为示例中的屏幕提供子小部件。
class InheritedWidgetTest extends StatefulWidget {
@override
State createState() => new InheritedWidgetTestState();
}
class InheritedWidgetTestState extends State<InheritedWidgetTest> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),body: Center(
child: Column(
children: [
ContextWidget('First'),ContextWidget('Second'),);
}
}
class ContextWidget extends StatelessWidget {
Navigator _getNavigator(BuildContext context,Widget child) {
return new Navigator(
onGenerateRoute: (RouteSettings settings) {
return new MaterialPageRoute(builder: (context) {
return child;
});
},);
}
final name;
ContextWidget(this.name);
@override
Widget build(BuildContext context) {
return MyInheritedWidget(
name: this.name,child: Expanded(
child: _getNavigator(
context,PageWidget(),);
}
}
class PageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
WidgetA(),TextButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Page1(),);
},child: Text('Go to page 1'),)
],);
}
}