【问题标题】:Pass data to multiple screens with inheritedwidget使用继承的小部件将数据传递到多个屏幕
【发布时间】:2021-03-31 06:32:15
【问题描述】:

关于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>();
  }
}

这是包含MyInheritedWidgetMyHomePageMyInheritedWidget 有两个孩子: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 内部有一个文本小部件,显示来自MyInheritedWidgetname 字段和另一个导航到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'),
        )
      ],
    );
  }
}

Page1Page2 每个都只有一个文本小部件,用于显示来自 MyInheritedWidgetname 字段。

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'),
      ),
      body: Text(myInheritedWidget.name),
    );
  }
}

在这种情况下,MyInheritedWidgetname 字段无法通过Page1Page2 访问,但可以通过WidgetA 访问。

现在让我们来看看这个问题:
据说可以从其所有后代访问InheritedWidget。后裔是什么意思?
MyHomePage 中,我知道WidgetAMyInheritedWidget 的后代。但是,Page1 也是MyInheritedWidget 的后代吗?
如果答案是否定的,我怎样才能让Page1 成为MyInheritedWidget 的后代?
我需要在MyInheritedWidget 中再次包装它吗?
如果有这样的导航链怎么办:Page1-> Page2 -> Page3 ... Page10我想在Page10中访问MyInheritedWidget,是否必须将每个页面都包装在MyInheritedWidget中?

【问题讨论】:

  • "[...] 但是,Page1 也是 MyInheritedWidget 的后代吗?" - 否 Page1 不是 MyInheritedWidget 的后代 - Page1 是主要Navigator的后代

标签: flutter inherited-widget


【解决方案1】:

正如@pskink 所说,MyHomePage 推送Page1,这是Navigator 的后代,它在MaterialApp 之下,而不是MyInheritedWidget。最简单的解决方案是在MaterialApp 上方创建MyInheritedWidget。这是我的代码(使用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, authService, _) {
        log.v('building MaterialApp with isAuth=${authService.isAuth}');
        return MaterialApp(

这是一个使用多个Navigators 来确定@​​987654334@ 范围的示例。小部件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'),
        )
      ],
    );
  }
}

【讨论】:

  • “最简单的解决方案是在 MaterialApp 之上创建 MyInheritedWidget” - 我认为使用 MaterialApp.builder 更好,但我同意,结果是一样的
  • @Patrick 我知道将MaterialApp 包装在MyInheritedWidget 内可以使其在全球范围内可访问。但我希望它只能被我的应用程序的某些部分访问。
  • 我猜你可以为你应用的不同部分添加额外的Navigators。有关该方法的讨论,请参阅 stackoverflow.com/questions/46502751/…,尽管它不是关于也没有提及 InheritedWidget
  • 我为多个Navigators添加了示例代码。
猜你喜欢
  • 2021-05-24
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 2021-07-01
  • 2021-03-30
  • 1970-01-01
相关资源
最近更新 更多