Flutter Navigator 2.0 通过 Navigator() 路由

标签 flutter flutter-web navigator flutter-navigation flutter-routes

我目前正在尝试使用新的 Flutter web beta 构建一个 web 应用程序。
问题是能够拥有历史记录,处理浏览器中的前进和后退按钮,并能够处理用户输入新的 Navigator 2.0 API 所需的 URL(至少从我的理解来看)。
目前只有少数可用资源,我正在尝试基于这些资源构建我的导航器。
我使用的资源:

  • (我的主要来源)'Learning Flutter’s new navigation and routing system'作者:约翰瑞恩
  • similar project (由 orestesgaolin 提供)但有一个页面管理器和更复杂的
  • publicly shared document by flutter关于新导航器

  • 我设法让后退和前进按钮,以及历史工作。但是,我很难处理页面切换(在 Navigator() 中)。在 John 的示例中,他管理 Navigator 小部件的 'page:' 数组中的不同站点(在 routeDelegater 中)。这对我来说似乎很奇怪,但我像这样尝试过,但并没有真正起作用(代码进一步向下)。
    在“页面:[]”中,我首先尝试触发 bool 值(如 show404),但这不是很干净,因此我的下一次尝试是按如下方式获取当前页面(在数组中):
    if(_currentPage.name == 'pages[0]') pageBuilds[0]
    
    这有点奏效,因为我可以输入段/matchit/0 并加载正确的页面,但是由于某种原因,“/”路由不再起作用,我收到了错误
    Navigator.onGenerateRoute was null, but the route named "/" was referenced 
    
    然后我尝试使用 'ongenerateRoute' 但这只是抛出了一堆错误。我有点新,所以也许我在那里做错了什么。但在我看来这不是正确的方法。这就是我目前陷入困境的地方。我不知道接下来该尝试什么,希望你们中的一些人可以帮助我。
    我的 Route-Delegater 如下所示(我也会在代码中包含我的注释,也许它可以帮助你们中的一些人,他们也希望了解 Navigator 2.0,了解正在发生的事情):
    /**
     * The RouteDelegate defines application specific behavious of how the router
     * learns about changes in the application state and how it responds to them. 
     * It listens to the RouteInformation Parser and the app state and builds the Navigator with
     * the current list of pages (immutable object used to set navigator's history stack).
     */
    
    //ChangeNotifier for the listeners as they are handled there
    //The popRoute is handled by 'PopNavigatorRouterDelegateMixin'
    class RoutesDelegater extends RouterDelegate<RoutePath>
        with ChangeNotifier, PopNavigatorRouterDelegateMixin<RoutePath> {
      //This is the state of the navigator widget (in build method)
      GlobalKey<NavigatorState> get navigatorKey => GlobalKey<NavigatorState>();
      //RoutesDelegater()  : navigatorKey = GlobalKey<NavigatorState>();
      MyPage _currentPage;
      bool show404 = false; //checks if we show the 404 page
    
      List<MyPage> pages = [
        MyPage('ProjektListe'),
        MyPage('StudiListe'),
        MyPage('PRView'),
      ];
    
      List<Page> pageBuilds = [
        MaterialPage(key: ValueKey('Unknown'), child: UnknownScreen()),
        MaterialPage(key: ValueKey('Homepage'), child: MyFirstHomepage()),
        MaterialPage(key: ValueKey('OtherScreen'), child: OtherScreen()),
      ];
    
      //currentConfiguration detects changes in the route information
      //It helps complete the browser history and (IMPORTANT) makes the browser back and forward buttons work
    
      RoutePath get currentConfiguration {
        if (show404) {
          return RoutePath.unknown();
        }
        if (_currentPage == null) return RoutePath.home();
        //if not 404 or homepage it is some other page
        return RoutePath.details(pages.indexOf(_currentPage));
      }
    
      @override
      Widget build(BuildContext context) {
        return Navigator(
            key: navigatorKey,
            pages: //List.of(pageBuilds),
                [
              //pageBuilds[1],
              if (show404)
                pageBuilds[0]
              else if (_currentPage != null)
                pageBuilds[1]
            ],
            onPopPage: (route, result) {
              if (!route.didPop(result)) {
                return false;
              }
              _currentPage = null;
              show404 = false;
              //we are using Changenotifier
              notifyListeners();
              return true;
            });
      }
    
      void _handleTapped(MyPage page) {
        _currentPage = page;
        notifyListeners();
      }
    
      @override
      Future<void> setNewRoutePath(RoutePath path) async {
        //Handle the unknown path
        if (path.isUnknown) {
          show404 = true;
          _currentPage = null;
          return;
        }
    
        if (path.isDetailPage) {
          //Check if Path id is valid
          if (path.id.isNegative || path.id > pages.length - 1) {
            show404 = true;
            return;
          }
          _currentPage = pages[path.id];
        } else {
          //homepage will be shown
          _currentPage = null;
        }
    
        show404 = false;
      }
    }
    
    我的 RoutingInformationParser 看起来像这样:
    /*
    * The RouteInformationParser takes the RouteInformation from RouteInformationProvider and
    * parses it into a user-defined data type.
    */
    
    class MyRoutesInformationParser extends RouteInformationParser<RoutePath> {
      @override
      Future<RoutePath> parseRouteInformation(
          RouteInformation routeInformation) async {
        //routeInformation is an object we get from the uri
        final uri = Uri.parse(routeInformation.location);
        // Handle '/' (Home Path)
        //Path segments are the segments seperated by /, if we don't have any we are on Home
        if (uri.pathSegments.length == 0) {
          return RoutePath.home();
        }
    
        //We have 2, as we have matchit/...
        if (uri.pathSegments.length == 2) {
          //If there is no 'matchit' in the first path segment the path is unknown
          if (uri.pathSegments.first != 'matchit') return RoutePath.unknown();
          //If we now have the correct first segment we can now handle the rest of the segment
          final remaining = uri.pathSegments.elementAt(1);
          final id = int.tryParse(remaining);
          //if it fails we return the unknown path
          if (id == null) return RoutePath.unknown();
          return RoutePath.details(id);
        }
    
        //Handling the unknown Path, e.g. user just typed anything in uri
        return RoutePath.unknown();
      }
    
      //THIS IS IMPORTANT: Here we restore the web history
      @override
      RouteInformation restoreRouteInformation(RoutePath path) {
        //Here we set the routeInformation which is used above, e.g. /404 for unknown page
        if (path.isUnknown) {
          return RouteInformation(location: '/404');
        }
        if (path.isHomePage) {
          return RouteInformation(location: '/');
        }
        //Any other page is handled here via /matchit/... <= the id of the path
        if (path.isDetailPage) {
          return RouteInformation(location: '/matchit/${path.id}');
        }
        //If none of the paths are hit
        return null;
      }
    }
    
    然后我们还有我的路由信息​​的数据类型:
    class RoutePath{
      final int id;
      final bool isUnknown;
    
      RoutePath.home()
          : id = null,
            isUnknown = false;
    
      //Details means here that it is any other side than Home or unknown
      RoutePath.details(this.id) : isUnknown = false;
    
      RoutePath.unknown()
          : id = null,
            isUnknown = true;
    
      //check if is on HomePage or other page, then either == null or != null
      //not needed for isInknown, as when unknown then = true as set above
      bool get isHomePage => id == null;
      bool get isDetailPage => id != null;
    }
    
    最后是我的 Homepage(),其中 InformationParser 和 Deleger 被初始化:
    class Homepage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _HomepageState();
    }
    
    class _HomepageState extends State<Homepage> {
      //initialize the RouteDelegater and Information Parser to be unsed further down
    
      RoutesDelegater _routesDelegater = RoutesDelegater();
      MyRoutesInformationParser _myRoutesInformationParser =
          MyRoutesInformationParser();
    
    /*
     * Relevant routing information for this build method:
     * We need to use the MaterialApp.router else we can't use routerDelegate and routeInformationParser.
     * Then we define the delegate and Information Parser (they are initiated above)
     */
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp.router(
            title: 'MatchIT',
            routerDelegate: _routesDelegater,
            routeInformationParser: _myRoutesInformationParser,
            theme: ThemeData(primarySwatch: Colors.blue),
            debugShowCheckedModeBanner: false);
      }
    }
    
    先感谢您!

    最佳答案

    我实际上设法通过在页面 [] 下的 RouteDelegator 中添加另一个在我的 Navigator() 中调用的函数来解决它:

     @override
      Widget build(BuildContext context) {
        return Navigator(
            key: navigatorKey,
            pages: [
              pageBuilds[1],
              if (show404)
                pageBuilds[0]
              else if (_currentPage != null)
                _getMyPage(_currentPage)
            ],
            onPopPage: (route, result) {
              if (!route.didPop(result)) {
                return false;
              }
              _currentPage = null;
              show404 = false;
              //we are using Changenotifier
              notifyListeners();
              return true;
            });
      }
    
      /*
       * This is where every other site than homepage and 404 is handled
       * to add another site to this application add the name to [List<MyPage> pages]
       * and then add the MaterialPage here
       */
    
      MaterialPage _getMyPage(MyPage currentPage) {
        if (currentPage.name == 'Login')
          return MaterialPage(key: ValueKey('LoginScreen'), child: OtherScreen());
        else
          return MaterialPage(
              key: ValueKey('ProfileScreen'), child: ResultScreen());
      }
    
    我还更改了上面列表中的名称(只是为了让你们能够理解代码):
    List<MyPage> pages = [
        MyPage('Login'),
        MyPage('Profile'),
      ];
    
      List<Page> pageBuilds = [
        MaterialPage(key: ValueKey('Unknown'), child: UnknownScreen()),
        MaterialPage(key: ValueKey('Homepage'), child: MyFirstHomepage()),
        MaterialPage(key: ValueKey('LoginScreen'), child: OtherScreen()),
        MaterialPage(key: ValueKey('ProfileScreen'), child: ResultScreen()),
      ];
    

    关于Flutter Navigator 2.0 通过 Navigator() 路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65142566/

    相关文章:

    flutter - 在 flutter 中向应用栏顶部添加阴影

    flutter - 如何在 flutter 中使用可注入(inject)和 get_it 的共享偏好?

    android - Flutter - 使用 Agora 的来电功能

    flutter - Flutter Web 应用程序中的文本可以搜索吗?

    firebase - Flutter Firebase -- 为 iOS、Android 和 Web 设置不同的部署目标

    c - 用宏注释函数

    javascript - 带有 firebase 通知的 Flutter web - subscribeToTopic

    Java Swing 我怎样才能完成像示例中这样的导航器

    javascript - 重定向到移动网站

    javascript - 如何将Dojo原型(prototype)集成到ICN中?