简介

咱们在flutter中能够应用Navigator.push或者Navigator.pushNamed办法来向Navigator中增加不同的页面,从而达到页面调整的目标。

个别状况下这样曾经足够了,然而有时候咱们有多个Navigator的状况下,下面的应用形式就不够用了。比方咱们有一个主页面app的Navigator,而后外面有一个匹配好友的性能,这个性能有多个页面,因为匹配好友性能的多个页面实际上是一个残缺的流程,所以这些页面须要被放在一个子Navigator中,并和主Navigator辨别开。

那么应该如何解决呢?

搭建主Navigator

主Navigator是咱们app的一些次要界面,这里咱们有三个界面,别离是主home界面,一个setting配置界面和好友匹配界面。

其中好友匹配界面蕴含了三个子界面,这三个子界面将会用到子路由。

先来看下主路由,主路由的状况跟一般的路由没啥区别,这里咱们首先定义和home和setting匹配的两个widget:HomePage和SettingsPage:

class HomePage extends StatelessWidget {  const HomePage({    super.key,  });  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: _buildAppBar(context),      body: Center(        child: Padding(          padding: const EdgeInsets.symmetric(horizontal: 24.0),          child: Column(            mainAxisSize: MainAxisSize.min,            children: const [              SizedBox(                width: 250,                height: 250,                child: Center(                  child: Icon(                    Icons.home,                    size: 175,                    color: Colors.blue,                  ),                ),              ),              SizedBox(height: 32),              Text(                '跳转到好友匹配页面',                textAlign: TextAlign.center,                style: TextStyle(                  fontSize: 24,                  fontWeight: FontWeight.bold,                ),              ),            ],          ),        ),      ),      floatingActionButton: FloatingActionButton(        onPressed: () {          Navigator.of(context).pushNamed(routeFriendMatch);        },        child: const Icon(Icons.add),      ),    );  }

HomePage很简略,它蕴含了一个floatingActionButton,当点击它的时候会调用 Navigator.pushNamed办法进行路由切换。

而后是SettingsPage,它是一个简略的Column:

class SettingsPage extends StatelessWidget {  const SettingsPage({    super.key,  });  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: _buildAppBar(),      body: SingleChildScrollView(        child: Column(          mainAxisSize: MainAxisSize.min,          children: List.generate(8, (index) {            return  ListTile(              title: Text('设置项$index'),            );          }),        ),      ),    );  }

最初一个页面是FriendMatchFlow,这个页面比较复杂,咱们在下一个再进行解说。

而后咱们为主路由在onGenerateRoute办法中进行定义:

void main() {  runApp(    MaterialApp(      onGenerateRoute: (settings) {        late Widget page;        if (settings.name == routeHome) {          page = const HomePage();        } else if (settings.name == routeSettings) {          page = const SettingsPage();        } else if (settings.name == routeFriendMatch) {          page = const FriendMatchFlow(            setupPageRoute: routeFriendMatchPage,          );        }        return MaterialPageRoute<dynamic>(          builder: (context) {            return page;          },          settings: settings,        );      },      debugShowCheckedModeBanner: false,    ),  );}

主路由很简略,跟一般的路由没有太多的区别。

构建子路由

接下来是构建子路由的步骤。在主路由中,如果路由的名称是routeFriendMatch,那么就会跳转到FriendMatchFlow。

而这个flow页面实际上是由几个子页面组成的:抉择好友页面,期待页面,匹配页面和匹配结束页面。

具体的页面代码这里就不写了,咱们次要来讲一下子路由的应用。

对于FriendMatchFlow来说,它自身是一个Navigator,所以咱们的build办法是这样的:

  Widget build(BuildContext context) {    return WillPopScope(      onWillPop: _isExitDesired,      child: Scaffold(        appBar: _buildFlowAppBar(),        body: Navigator(          key: _navigatorKey,          initialRoute: widget.setupPageRoute,          onGenerateRoute: _onGenerateRoute,        ),      ),    );  }

因为他须要依据用户的不同点击来进行外部路由的切换,所以须要保留对以后子Navigator的利用,所以这里FriendMatchFlow是一个StatefulWidget,并且下面的_navigatorKey是一个GlobalKey对象,以提供对子Navigator的援用:

  final _navigatorKey = GlobalKey<NavigatorState>();

这里的_onGenerateRoute办法,跟主路由也是很相似的,次要定义的是子路由中页面的跳转:

  Route _onGenerateRoute(RouteSettings settings) {    late Widget page;    switch (settings.name) {      case routeFriendMatchPage:        page = WaitingPage(          message: '匹配左近的好友...',          onWaitComplete: _onDiscoveryComplete,        );        break;      case routeFriendSelectPage:        page = SelectFriendPage(          onFriendSelected: _onFriendSelected,        );        break;      case routeFriendConnectingPage:        page = WaitingPage(          message: '匹配中...',          onWaitComplete: _onConnectionEstablished,        );        break;      case routeFriendFinishedPage:        page = FinishedPage(          onFinishPressed: _exitSetup,        );        break;    }

这里的on*Selected是VoidCallback回调,用来进行路由的切换:

  void _onDiscoveryComplete() {    _navigatorKey.currentState!.pushNamed(routeFriendSelectPage);  }  void _onFriendSelected(String deviceId) {    _navigatorKey.currentState!.pushNamed(routeFriendConnectingPage);  }  void _onConnectionEstablished() {    _navigatorKey.currentState!.pushNamed(routeFriendFinishedPage);  }

能够看到下面的路由切换实际上是在子路由上切换,跟父路由无关。

如果想要间接从子路由跳出到父路由该怎么解决呢?很简略,调用Navigator.of的pop办法即可:

  void _exitSetup() {    Navigator.of(context).pop();  }

这里的context默认是全局的context,所以会导致主路由的跳转变动。

总结

以上的代码运行后果如下:

尽管下面的例子看起来简单,然而大家只有记住了不同的路由应用不同的Navigator范畴进行跳转就行了。

本文的例子:https://github.com/ddean2009/learn-flutter.git