【问题标题】:Inherited widgets and navigator继承的小部件和导航器
【发布时间】:2019-10-24 12:02:09
【问题描述】:

我找到了一些关于这个 [here, here] 的答案,但没有一个能完全回答我的问题。

我将使用包provider 来描述我的问题,因为它大大减少了样板代码。

我想做的是在(且仅在)调用路由时注入依赖项。我可以通过在onGenerateRoute 上做这样的事情来实现这一点:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Routes Demo',
        initialRoute: '/',
        onGenerateRoute: (settings) {
          switch (settings.name) {
            case '/':
              return MaterialPageRoute(builder: (_) => HomePage());
            case '/firstPage':
              return MaterialPageRoute(
                builder: (_) => Provider(
                      builder: (_) => MyComplexClass(),
                      child: FirstPage(),
                    ),
              );
            case '/secondPage':
              return MaterialPageRoute(builder: (_) => SecondPage());
            default:
              return MaterialPageRoute(
                builder: (_) => Scaffold(
                      body: Center(
                        child: Text('Route does not exists'),
                      ),
                    ),
              );
          }
        });
  }
}

class MyComplexClass {
  String message = 'UUUH I am so complex';
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          RaisedButton(
              child: Text('Go to first page'),
              onPressed: () {
                Navigator.pushNamed(context, '/firstPage');
              }),
        ],
      ),
    ));
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final myComplexClass = Provider.of<MyComplexClass>(context);
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Center(
              child: Text(myComplexClass.message),
            ),
            RaisedButton(
              child: Text('Go to second page'),
              onPressed: () {
                Navigator.pushNamed(context, '/secondPage');
              },
            )
          ],
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final myComplexClass = Provider.of<MyComplexClass>(context);
    return Scaffold(
      body: Center(
        child: Text(myComplexClass.message),
      ),
    );
  }
}

这适用于“/firstPage”,但是一旦我从“firstPage”内部推送另一条路线,上下文就会丢失并且我无法访问MyComplexClass,因为导航器与MaterialApp 的下一条路线将失去注入 MyComplexClass 的上下文,我无法找到一个优雅的解决方案。

这是我们最终得到的导航器堆栈:

正如我们所见,SecondPage 不是Provider 的子代,因此存在问题。

我不想在 MainApp 上一次注入所有依赖项,我想在需要时注入它们。
每次我需要另一个“折叠”时,我都会考虑创建新的导航器,但这似乎很快就变得非常混乱。

我该如何解决这个问题?

【问题讨论】:

  • "I cannot manage to find a elegant solution to this." - 究竟是为了什么?你不能从第二条路线访问你的InheritedWidget`吗?
  • 是的,一旦我在 '/foo' 内推送一条新路由,它就会丢失 InheritedWidget 所在的上下文。
  • 所以你的意思是inheritFromWidgetExactType方法返回null?如果是这样,请发布您的代码
  • 我编辑了问题并添加了完整的代码示例,因此我的问题变得更加清晰。
  • 例如,让您的Provider 成为MyApp 的父级(或作为MaterialApp 的父级)

标签: flutter


【解决方案1】:

在以下示例中,路由//login 都可以访问Provider.of&lt;int&gt;,但路由/other 不能。

有两种解决方案:

  • StatefulWidgetProvider.value 相结合,包裹每条路线。

例子:

class Foo extends StatefulWidget {
  @override
  _FooState createState() => _FooState();
}

class _FooState extends State<Foo> {
  int myState = 42;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        '/': (_) => Provider.value(value: myState, child: Home()),
        '/login': (_) => Provider.value(value: myState, child: Login()),
        '/other': (_) => Other(),
      },
    );
  }
}
  • 封装MaterialAppProxyProvider 的私有占位符类型:

例子:

class _Scope<T> {
  _Scope(this.value);

  final T value;
}

// ...

Widget build(BuildContext context) {
  Provider(
    builder: (_) => _Scope(42),
    child: MaterialApp(
      routes: {
        '/': (_) => ProxyProvider<_Scope<int>, int>(
            builder: (_, scope, __) => scope.value, child: Home()),
        '/login': (_) => ProxyProvider<_Scope<int>, int>(
            builder: (_, scope, __) => scope.value, child: Login()),
        '/other': (_) => Other(),
      },
    ),
  );
}

【讨论】:

    猜你喜欢
    • 2020-04-16
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2023-03-03
    • 2020-05-14
    • 1970-01-01
    • 2012-02-17
    相关资源
    最近更新 更多