【问题标题】:Issue regarding nested MaterialApp.router() in Flutter Navigator 2.0关于 Flutter Navigator 2.0 中嵌套 MaterialApp.router() 的问题
【发布时间】:2021-07-18 02:47:39
【问题描述】:

问这个问题表示我正在尝试使用 Navigator 2.0 为我的 Flutter Web 应用程序创建一个嵌套的 Navigator。下面是我的应用程序的起点。

void main() {
  runApp(App());
}


class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {

  @override
  Widget build(BuildContext context) {

    return MaterialApp.router(
        routeInformationParser: AppRouteParser(), routerDelegate: AppRouterDelegate(),
      title: "Demo",
    );
  }

}

如您所见,我添加了一个 MaterialApp.router() 来处理所有顶层导航。

现在我想在这个导航器中添加一个嵌套导航器,它的工作方式与上面相同,并且会正确处理 url 更改。这就是为什么我决定在内部使用与嵌套 Navigator 相同的 MaterialApp.router() 小部件。

执行此操作后一切正常,但我得到两个调试横幅,如下图所示:

这让我怀疑我是否使用了正确的方法来获得结果。

子 Navigator 属于根导航器的 Page1 小部件,如下所示是根 MaterialApp.router 的 Navigator 小部件:

class AppRouterDelegate extends RouterDelegate<AppRoute>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoute> {

  final GlobalKey<NavigatorState> _navigatorKey;

  bool isPage1A = false;
  bool isPage1B = false;
  bool isUnknown = false;

  AppRouterDelegate() : _navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {

     return Navigator(
         pages: [
           MaterialPage(key: ValueKey("Page 1"),child: Page1(_valueChangeCallback)),
           if(isPage1A)
             MaterialPage(key: ValueKey("Page 1A"),child: Page1A(_valueChangeCallback)),
           if(isPage1B)
             MaterialPage(key: ValueKey("Page 1B"),child: Page1B(_valueChangeCallback)),
          /* if(isUnknown)
             MaterialPage(key: ValueKey("404"),child: TestPage()) */
         ],
         onPopPage: (route,result){print("Pop !!!!");  return route.didPop(result);}
     );
  }


  _valueChangeCallback(bool value,String subPage,[String subPage2]) {

    //print("Value change callback");

      if(subPage2 == null) {
        if(subPage == "A")
          isPage1A = value;
        else if(subPage == "B")
          isPage1B = value;
      }
      else {
        if(subPage2 == "B") {
          isPage1A = !value;
          isPage1B = value;
        }
        else if(subPage2 == "A") {
          isPage1A = value;
          isPage1B = !value;
        }
      }
      notifyListeners();
  }

下面是子 MaterialApp.router 所在的 Page1 小部件:

class Page1 extends StatefulWidget {

  Function valueChangeCallback;

  Page1(this.valueChangeCallback);

  @override
  _Page1State createState() => _Page1State();
}

class _Page1State extends State<Page1> {

  @override
  Widget build(BuildContext context) {

    print("Page 1");

    return Scaffold(
      body: Column(
        children: [
          InkWell(
            onTap: () {
              widget.valueChangeCallback(true,"A");
            },
            child: Text("Move to Sub Pages")
          ),
          Expanded(child: MaterialApp.router(routeInformationParser: NestedAppRouteInformationParser(), routerDelegate: NestedAppRouterDelegate())),
        ],
      ),
    );
  }
}

【问题讨论】:

    标签: flutter flutter-web


    【解决方案1】:

    如果你查看 app.dart MaterialApp 是一个方便的小部件,它包含了一些“材料设计应用程序通常需要的小部件”。

    如果您要使用默认构造函数,则会为您配置顶级 Navigator 对象。

    MaterialApp.router() 是另一个便利。 “创建一个使用 [Router] 而不是 [Navigator] 的 [MaterialApp]。”

    路由器构造函数为您提供了一种创建 MaterialApp 并配置和返回自定义 Navigator 的方法。

    当您使用此构造函数时,您所做的是将后代小部件包装在 MaterialApp 必须提供的所有便利小部件中(包括调试横幅)。

    对于嵌套路由器,您要做的只是直接使用 Router() 小部件,这样您就可以避免在应用初始化期间调用 MaterialApp 为您提供的所有附加功能。

    另外值得注意的是,理想情况下,每个应用程序应该只有一个信息解析器。 根据 router.dart 中的注释,您应该将 null 传递给嵌套路由器 Wdiget。

    "To opt out of URL updates entirely, pass null for [routeInformationProvider]
    /// and [routeInformationParser]. This is not recommended in general, but may be
    /// appropriate in the following cases:
    ///
    /// * The application does not target the web platform.
    ///
    /// * **There are multiple router widgets in the application. Only one [Router]
    ///   widget should update the URL (typically the top-most one created by the
    ///   [WidgetsApp.router], [MaterialApp.router], or [CupertinoApp.router]).**
    ///
    /// * The application does not need to implement in-app navigation using the
    ///   browser's back and forward buttons."
    
    
        class _Page1State extends State<Page1> {
    
      @override
      Widget build(BuildContext context) {
    
        print("Page 1");
    
        return Scaffold(
          body: Column(
            children: [
              InkWell(
                onTap: () {
                  widget.valueChangeCallback(true,"A");
                },
                child: Text("Move to Sub Pages")
              ),
              Expanded(child: Router(routeInformationParser: null, routerDelegate: NestedAppRouterDelegate(), backButtonDispatcher: ChildBackButtonDispatcher(Router.of(context).backButtonDispatcher),)),
            ],
          ),
        );
      }
    

    还提供如图所示的子后退按钮调度程序将允许您在执行后退按钮按下时联系父路由器...希望对您有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-24
      • 2021-03-16
      • 2021-02-22
      • 2019-08-08
      • 2020-11-22
      • 2021-06-22
      • 1970-01-01
      • 2021-04-05
      相关资源
      最近更新 更多