2023-06-24 16:43:58 來源 : 腳本之家
我們在flutter中可以使用Navigator.push或者Navigator.pushNamed方法來向Navigator中添加不同的頁面,從而達到頁面調(diào)整的目的。
(資料圖片僅供參考)
一般情況下這樣已經(jīng)足夠了,但是有時候我們有多個Navigator的情況下,上面的使用方式就不夠用了。比如我們有一個主頁面app的Navigator,然后里面有一個匹配好友的功能,這個功能有多個頁面,因為匹配好友功能的多個頁面實際上是一個完整的流程,所以這些頁面需要被放在一個子Navigator中,并和主Navigator區(qū)分開。
那么應(yīng)該如何處理呢?
主Navigator是我們app的一些主要界面,這里我們有三個界面,分別是主home界面,一個setting配置界面和好友匹配界面。
其中好友匹配界面包含了三個子界面,這三個子界面將會用到子路由。
先來看下主路由,主路由的情況跟普通的路由沒啥區(qū)別,這里我們首先定義和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( "跳轉(zhuǎn)到好友匹配頁面", 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,當點擊它的時候會調(diào)用 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("設(shè)置項$index"), ); }), ), ), ); }
最后一個頁面是FriendMatchFlow,這個頁面比較復(fù)雜,我們在下一個再進行講解。
然后我們?yōu)橹髀酚稍趏nGenerateRoute方法中進行定義:
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( builder: (context) { return page; }, settings: settings, ); }, debugShowCheckedModeBanner: false, ), ); }
主路由很簡單,跟普通的路由沒有太多的區(qū)別。
接下來是構(gòu)建子路由的步驟。在主路由中,如果路由的名稱是routeFriendMatch,那么就會跳轉(zhuǎn)到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, ), ), ); }
因為他需要根據(jù)用戶的不同點擊來進行內(nèi)部路由的切換,所以需要保存對當前子Navigator的應(yīng)用,所以這里FriendMatchFlow是一個StatefulWidget,并且上面的_navigatorKey是一個GlobalKey對象,以提供對子Navigator的引用:
final _navigatorKey = GlobalKey();
這里的_onGenerateRoute方法,跟主路由也是很類似的,主要定義的是子路由中頁面的跳轉(zhuǎn):
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回調(diào),用來進行路由的切換:
void _onDiscoveryComplete() { _navigatorKey.currentState!.pushNamed(routeFriendSelectPage); } void _onFriendSelected(String deviceId) { _navigatorKey.currentState!.pushNamed(routeFriendConnectingPage); } void _onConnectionEstablished() { _navigatorKey.currentState!.pushNamed(routeFriendFinishedPage); }
可以看到上面的路由切換實際上是在子路由上切換,跟父路由無關(guān)。
如果想要直接從子路由跳出到父路由該怎么處理呢?很簡單,調(diào)用Navigator.of的pop方法即可:
void _exitSetup() { Navigator.of(context).pop(); }
這里的context默認是全局的context,所以會導(dǎo)致主路由的跳轉(zhuǎn)變化。
以上的代碼運行結(jié)果如下:
雖然上面的例子看起來復(fù)雜,但是大家只要記住了不同的路由使用不同的Navigator范圍進行跳轉(zhuǎn)就行了。
到此這篇關(guān)于Flutter學(xué)習(xí)之創(chuàng)建一個內(nèi)嵌的navigation詳解的文章就介紹到這了,更多相關(guān)Flutter創(chuàng)建內(nèi)嵌navigation內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!