首页 > 解决方案 > 继承的小部件和导航器

问题描述

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

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

我想要做的是在(且仅在)调用路由时注入依赖项。我可以通过做这样的事情来实现这一点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 上一次注入所有依赖项,我想在需要时注入它们。
每次我需要另一个“折叠”时,我都考虑过创建新的导航器,但这似乎很快就变得非常混乱。

我该如何解决这个问题?

标签: flutter

解决方案


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

有两种解决方案:

  • AStatefulWidgetProvider.value包裹每条路线的 a 相结合。

例子:

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

推荐阅读