Flutter學(xué)習(xí)之創(chuàng)建一個內(nèi)嵌的navigation詳解
簡介
我們在flutter中可以使用Navigator.push或者Navigator.pushNamed方法來向Navigator中添加不同的頁面,從而達(dá)到頁面調(diào)整的目的。
一般情況下這樣已經(jīng)足夠了,但是有時候我們有多個Navigator的情況下,上面的使用方式就不夠用了。比如我們有一個主頁面app的Navigator,然后里面有一個匹配好友的功能,這個功能有多個頁面,因?yàn)槠ヅ浜糜压δ艿亩鄠€頁面實(shí)際上是一個完整的流程,所以這些頁面需要被放在一個子Navigator中,并和主Navigator區(qū)分開。
那么應(yīng)該如何處理呢?
搭建主Navigator
主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,當(dāng)點(diǎn)擊它的時候會調(diào)用 Navigator.pushNamed方法進(jìn)行路由切換。
然后是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è)置項(xiàng)$index'), ); }), ), ), ); }
最后一個頁面是FriendMatchFlow,這個頁面比較復(fù)雜,我們在下一個再進(jìn)行講解。
然后我們?yōu)橹髀酚稍趏nGenerateRoute方法中進(jìn)行定義:
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, ), ); }
主路由很簡單,跟普通的路由沒有太多的區(qū)別。
構(gòu)建子路由
接下來是構(gòu)建子路由的步驟。在主路由中,如果路由的名稱是routeFriendMatch,那么就會跳轉(zhuǎn)到FriendMatchFlow。
而這個flow頁面實(shí)際上是由幾個子頁面組成的:選擇好友頁面,等待頁面,匹配頁面和匹配完畢頁面。
具體的頁面代碼這里就不寫了,我們主要來講一下子路由的使用。
對于FriendMatchFlow來說,它本身是一個Navigator,所以我們的build方法是這樣的:
Widget build(BuildContext context) { return WillPopScope( onWillPop: _isExitDesired, child: Scaffold( appBar: _buildFlowAppBar(), body: Navigator( key: _navigatorKey, initialRoute: widget.setupPageRoute, onGenerateRoute: _onGenerateRoute, ), ), ); }
因?yàn)樗枰鶕?jù)用戶的不同點(diǎn)擊來進(jìn)行內(nèi)部路由的切換,所以需要保存對當(dāng)前子Navigator的應(yīng)用,所以這里FriendMatchFlow是一個StatefulWidget,并且上面的_navigatorKey是一個GlobalKey對象,以提供對子Navigator的引用:
final _navigatorKey = GlobalKey<NavigatorState>();
這里的_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),用來進(jìn)行路由的切換:
void _onDiscoveryComplete() { _navigatorKey.currentState!.pushNamed(routeFriendSelectPage); } void _onFriendSelected(String deviceId) { _navigatorKey.currentState!.pushNamed(routeFriendConnectingPage); } void _onConnectionEstablished() { _navigatorKey.currentState!.pushNamed(routeFriendFinishedPage); }
可以看到上面的路由切換實(shí)際上是在子路由上切換,跟父路由無關(guān)。
如果想要直接從子路由跳出到父路由該怎么處理呢?很簡單,調(diào)用Navigator.of的pop方法即可:
void _exitSetup() { Navigator.of(context).pop(); }
這里的context默認(rèn)是全局的context,所以會導(dǎo)致主路由的跳轉(zhuǎn)變化。
總結(jié)
以上的代碼運(yùn)行結(jié)果如下:
雖然上面的例子看起來復(fù)雜,但是大家只要記住了不同的路由使用不同的Navigator范圍進(jìn)行跳轉(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)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用xutils3.0進(jìn)行下載項(xiàng)目更新
這篇文章主要介紹了用xutils3.0進(jìn)行下載項(xiàng)目更新的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-08-08Android自定義帶增長動畫和點(diǎn)擊彈窗提示效果的柱狀圖DEMO
這篇文章主要介紹了Android自定義帶增長動畫和點(diǎn)擊彈窗提示效果的柱狀圖的相關(guān)資料,非常不錯具有一定的參考借鑒價值,需要的朋友可以參考下2016-11-11Android答題APP的設(shè)計與實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Android答題APP的設(shè)計與實(shí)現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01Android實(shí)現(xiàn)Banner界面廣告圖片循環(huán)輪播(包括實(shí)現(xiàn)手動滑動循環(huán))
這篇文章主要介紹了Android實(shí)現(xiàn)Banner界面廣告圖片循環(huán)輪播(包括實(shí)現(xiàn)手動滑動循環(huán))的相關(guān)資料,需要的朋友可以參考下2016-02-02Android中實(shí)現(xiàn)淘寶購物車RecyclerView或LIstView的嵌套選擇的邏輯
這篇文章主要介紹了Android中實(shí)現(xiàn)淘寶購物車RecyclerView或LIstView的嵌套選擇的邏輯,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12Material Design系列之Behavior實(shí)現(xiàn)支付密碼彈窗和商品屬性選擇效果
這篇文章主要為大家詳細(xì)介紹了Material Design系列之Behavior實(shí)現(xiàn)支付密碼彈窗和商品屬性選擇效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09Android手機(jī)獲取root權(quán)限并實(shí)現(xiàn)關(guān)機(jī)重啟功能的方法
這篇文章主要介紹了Android手機(jī)獲取root權(quán)限并實(shí)現(xiàn)關(guān)機(jī)重啟功能的方法,是Android程序設(shè)計中非常重要的技巧,需要的朋友可以參考下2014-08-08