使用提供程序重写嵌套的 Navigator 2.0 示例

Dam*_*ast 5 dart flutter flutter-web

我希望重写官方示例,以编写带有底部导航的嵌套导航器。具体来说,我想使用提供程序编写另一个实现来提升状态,而不是将回调传递到页面,就像这里发生的 ?handleBookTapped?。

问:如何使用 Provider 将 BookAppState 传递给页面,同时在不丢失选项卡状态的情况下正确更新外部和内部导航器。

class InnerRouterDelegate extends RouterDelegate<BookRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<BookRoutePath> {
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
  BooksAppState get appState => _appState;
  BooksAppState _appState;
  set appState(BooksAppState value) {
    if (value == _appState) {
      return;
    }
    _appState = value;
    notifyListeners();
  }

  InnerRouterDelegate(this._appState);

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: navigatorKey,
      pages: [
        if (appState.selectedIndex == 0) ...[
          FadeAnimationPage(
            child: BooksListScreen(
              books: appState.books,
              onTapped: _handleBookTapped,
            ),
            key: ValueKey('BooksListPage'),
          ),
          if (appState.selectedBook != null)
            MaterialPage(
              key: ValueKey(appState.selectedBook),
              child: BookDetailsScreen(book: appState.selectedBook),
            ),
        ] else
          FadeAnimationPage(
            child: SettingsScreen(),
            key: ValueKey('SettingsPage'),
          ),
      ],
      onPopPage: (route, result) {
        appState.selectedBook = null;
        notifyListeners();
        return route.didPop(result);
      },
    );
  }

  @override
  Future<void> setNewRoutePath(BookRoutePath path) async {
    // This is not required for inner router delegate because it does not
    // parse route
    assert(false);
  }

  void _handleBookTapped(Book book) {
    appState.selectedBook = book;
    notifyListeners();
  }
}

Run Code Online (Sandbox Code Playgroud)

Rod*_*y R 4

    \n
  1. 添加MultiProvider到您的应用程序(因为您可能会使用多个应用程序)。
  2. \n
\n
    Future<void> main() async {\n      WidgetsFlutterBinding.ensureInitialized();\n    \n      runApp(\n        /// Providers are above [MyApp] instead of inside it, so that tests\n        /// can use [MyApp] while mocking the providers\n        MultiProvider(\n          providers: [\n            ChangeNotifierProvider(create: (_) => MyAppState()),\n            //ChangeNotifierProvider(create: (_) => Counter()),\n          ],\n          child: RootRouter(),\n        ),\n      );\n    \n    }\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. \xc3\x92nInnerRouterDelegate用于.watch捕获构建内的索引更改。
  2. \n
\n
@override\n  Widget build(BuildContext context) {\n    var idx = context.watch<MyAppState>().selectedBottomNavIndex;\n    return Navigator(\n...\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. bottomNavigationBar替换为(appState.context.watch<MyAppState>().注意,我使用枚举作为索引,与官方示例略有不同)
  2. \n
\n
bottomNavigationBar:\n        BottomNavigationBar(\n          type: BottomNavigationBarType.fixed,\n          items: BottomNavigationBarItems.items(),\n          currentIndex: context.watch<MyAppState>().selectedBottomNavIndex.index,\n          //currentIndex: appState.selectedBottomNavIndex.index, //replace\n          onTap: (newIndex) {\n            context.read<MyAppState>().selectedBottomNavIndex= NavItem.values[newIndex];\n            //appState.selectedBottomNavIndex = NavItem.values[newIndex]; //replace\n          },\n        ),\n
Run Code Online (Sandbox Code Playgroud)\n

这将使其适用于移动设备。还有很多网络内容需要更新,并且代码需要清理/删除。appState变量变得过时。

\n