1. 程式人生 > >【Flutter 實戰】路由堆疊詳解

【Flutter 實戰】路由堆疊詳解

![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451063-89853048.png) > **老孟導讀**:Flutter中路由是非常重要的部分,任何一個應用程式都離不開路由管理,此文講解路由相關方法的使用和**路由堆疊**的變化。 Flutter 路由管理中有兩個非常重要的概念: - **Route**:路由是應用程式**頁面**的抽象,對應 Android 中 Activity 和 iOS 中的 ViewController,由 Navigator 管理。 - **Navigator**:Navigator 是一個元件,管理和維護一個基於**堆疊**的歷史記錄,通過 push 和 pop 進行頁面的跳轉。 #### push 和 pop 假設現在有2個頁面 A 和 B,A中有一個按鈕,點選跳轉到 B 頁面,A 頁面程式碼: ```dart class APage extends StatelessWidget { @override Widget build(BuildContext context) { return Container( alignment: Alignment.center, child: RaisedButton( child: Text('A 頁面'), onPressed: () { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return BPage(); })); }, ), ); } } ``` B 頁面程式碼: ```dart class BPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Container( alignment: Alignment.center, child: RaisedButton( child: Text('B 頁面'), onPressed: () { }, ), ), ); } } ``` ![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451506-810717733.gif) 當應用程式位於A頁面時,**路由堆疊**中只有A,點選按鈕跳轉到B頁面,路由堆疊中有 B 和 A,且 B 處於棧頂。 ![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451685-2025256525.png) 點選 B 頁面的按鈕返回到 A 頁面,修改 B 頁面按鈕點選事件: ```dart RaisedButton( child: Text('B 頁面'), onPressed: () { Navigator.of(context).pop(); }, ) ``` 路由堆疊的變化: ![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451872-1533537610.png) 上面案例的效果是從 B 頁面跳轉到 A 頁面,那是否也可以使用 push 方法?修改 B 頁面按鈕點選事件: ```dart RaisedButton( child: Text('B 頁面'), onPressed: () { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return APage(); })); }, ) ``` 從效果上看也可以跳轉到 A 頁面,路由堆疊: ![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073452074-57038397.png) **那是否可以使用 push 代替 pop 呢?** 答案肯定是不可以的, 1. 試想如下場景,進入購物App,展示購物列表,點選其中一個進入商品詳細頁面,使用 push 再次進入購物列表,然後在進入商品詳細頁面...,如此反覆,路由堆疊中將會存放大量的購物列表和商品詳細頁面的路由,點選返回按鈕,會將反覆顯示購物列表和商品詳細頁面。 2. 頁面切換時路由動畫 push 和 pop 是不同。 #### maybePop 和 canPop 上面案例如果點選 A 頁面按鈕直接呼叫 pop 會如何? ```dart RaisedButton( child: Text('A 頁面'), onPressed: () { Navigator.of(context).pop(); }, ) ``` 在 A 頁面時路由堆疊中只有 A,呼叫 pop 後,路由堆疊變化: ![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073452208-1992480782.png) 此時路由堆疊為空,沒有可顯示的頁面,應用程式將會退出或者黑屏,好的使用者體驗不應如此,此時可以使用 maybePop,maybePop 只在路由堆疊有可彈出路由時才會彈出路由。 上面的案例在 A 頁面執行maybePop: ```dart RaisedButton( child: Text('A 頁面'), onPressed: () { Navigator.of(context).maybePop(); }, ) ``` 點選後不會出現彈出路由,因為當前路由堆疊中只有 A,在 B頁面執行maybePop,將會返回到 A 頁面。 也可以通過 canPop 判斷當前是否可以 pop: ```dart RaisedButton( child: Text('B 頁面'), onPressed: () { if(Navigator.of(context).canPop()){ Navigator.of(context).pop(); } }, ) ``` #### pushNamed pushNamed 是命名路由的方式,需要在 MaterialApp 中配置路由名稱: ```dart MaterialApp( title: 'Flutter Demo', routes: