继承的小部件和导航器

时间:2019-06-10 04:12:18

标签: flutter

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

我将使用软件包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的上下文,我无法设法找到一种完美的解决方案。

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

我们可以看到SecondPage不是Provider的子级,因此是问题。

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

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

在以下示例中,路由//login都可以访问Provider.of<int>,而路由/other无法访问。

有两种解决方案:

  • 一个StatefulWidget与一个Provider.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(),
      },
    ),
  );
}