穿梭在不同的畫面中 - 固定名稱路由法

紅寶鐵軌客
Join to follow...
Follow/Unfollow Writer: 紅寶鐵軌客
By following, you’ll receive notifications when this author publishes new articles.
Don't wait! Sign up to follow this writer.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.
寫程式中、折磨中、享受中 ......
694   0  
·
2021/06/03
·
6 mins read


前文所述,Flutter 有四種 Navigation & Routing 的方式:

N1
直接導航
直接給指定 screen 名稱
N2 固定名稱路由 透過路由跳到指定的 screen 名稱
N3 動態名稱路由 目的地由 widget 中取出,或用 onGenerateRoute()  
N4 動態名稱路由 2.0 使用 State:有 Page 及 Route 兩個新的 API

我們已經學過了「N1/直接導航法」這種直接導航的方式,說直白的,就是把要去的 screen 包成一個 Route,好處是很直接,小缺點是如果常常要去這個 screen,就要寫很多次,所以接下來這種,「N2 / 固定名稱路由法」,說白了,就是一個懶人法,把所有的 screens 列一個表,再給每個 screen 對應一個「路徑名稱」,這樣如果要重複呼叫,就簡單多了。

N2 / 固定名稱路由法

其實這種用「路徑名稱」的方法在各種網站的開發平台上,早就已經用很久了,就叫 routes,路由,Flutter 也沒搞怪,一樣也叫做 routes,用法也很簡單:

  1. 先建立一個 routes,也就是「路徑名稱」對應 screen 的表;
  2. 再將要去的 screen 用 Navigator.pushNamed(路徑名稱) 來呼叫,App 就會跳轉到該頁了。 

講半天,不如直接上碼,如果你剛進來,我們目前的程式碼的開發是停留在這裡:

Flutter 程式寫作風格與管理 Code Organization — 將程式碼依照功能,放入適當的 folder 中,及,取一個好的名稱...
WriterShelf 思書: 紅寶鐵軌客

我們會從這裡開始修改程式,如果你是中途插隊進來了,可以打開來參考裡面的程式碼。

先打開 main.dart,routes 是要寫在 MaterialApp 這個 Widget 裡面:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: '/',
      routes: {
        '/': (context) => MyHomePage(title: 'Happy Recorder v0.0'),
        '/audio': (context) => AudioSession(),
      },
    );
  }
}

我們只改了以下:

  • 第 9~13 行:原來是直接跳到 home: MyHomePage(title: 'Happy Recorder v0.0'), 我們現在改成:
    • 第 9 行:initialRoute 是 App 一開始要去的路徑名稱,一般都設為 '/',也就是無名,我們稱之為 root,網頁根目錄。
    • 第 10~13 行:就是建立這個 App 的 routes,我們就只有兩個,一個是 root,另一個路徑名稱我們取為 audio,對應到 AudioSession screen。

再來就是將原來的 Navigator.push () 改成 Navigator.pushNamed(路徑名稱),我們目前只有一個 screen 有直接連結跳轉,就是 MyHomePage.dart,打開它,把 push() 改成 pushName(/audio):

floatingActionButton: FloatingActionButton(
  //onPressed: _incrementCounter,
  onPressed: () {
    Navigator.pushNamed(context, '/audio');
  },
  ...
),

我們也只改了一行,找到 FloatingActionButton 中的 onPressed,也就是上圖的第 4 行,將原先的落落長的 Navigator.push( content, MaterialPageRoute......... ) 改成很精簡的 Navigator.pushNamed( context,  '/audio' ),就好了,這樣是不是看起來清爽多了。

這樣就改好了。啥!就只改了四行程式碼!沒錯,就是這麼簡單。

好啦,現在我們可以試試看了,請使用 Web 模擬器(因為 App 沒有網址列),執行 run,很好,如我們所預期的,我們看到路徑名稱 audio 出現在網址上了,如下圖:

我們也稱這種網址為「友善網址」:一個讓使用者可以讀懂的網址。

很不幸的,這也不是我們要的導航方式,我們需要一個網址可以直接連到錄音檔的:url.com/audio/class1,但是我們有更接近了。

除此之外,這方法還有其他問題:

  • 直接打路徑名稱 audio 在網址上,會動嗎?很可惜,不會。
  • 同樣的,各位也要測試一下瀏覽器的倒退前進鍵,你應該很快就會發現還是很怪怪的,有的時候可以倒退,有時不行,你現在知道這倒退前進鍵真的很難搞了吧。

 

更多的 navigation 功能

當所有的 screens 都有路徑名稱後,navigator 可以做的事就不止是 push/pop/pushName() 這種「簡單」的堆疊動作而已了,它可以做的更多的「堆疊更改」動作了,例如:

  • pushReplacementNamed:
    • 使用情境像是登入成功後,你不會想讓使用者按倒退鍵時再看到登入 screen;
    • pushReplacementNamed 會將 stack 上的路徑名稱改掉,這個跟下面的 popAndPushNamed 很像,只是這個會使用切換畫面中的「 enter animation 進入動畫」,動畫的部分有點小複雜,我們先跳過,真有興趣可以先看這裡
  • popAndPushNamed:
    • 跟 pushReplacementNamed 幾乎一樣,stack 先 pop 出舊的,再 push 進新的,切換的動作沒差別,只是這個會使用「 exit animation 離開動畫」。
  • pushNamedAndRemoveUntil:
    • 寫法:Navigator.of(context).pushNamedAndRemoveUntil('/screen4', ModalRoute.withName('/screen1')),它會清 Stack 清到 route screen1 然後 push screen4 進去,
    • 使用情境:例如使用者 logout,Navigator Stack 必須要清空然後 push screen4 進去,寫法:Navigator.of(context).pushNamedAndRemoveUntil('/screen4', (Route route) => false);
  • popUntil:
    • 寫法:Navigator.popUntil(context, ModalRoute.withName('/screen2')) ,它會一直 Pop navigator 的 stack 直到 screen2 出現為止。
  • 還有一堆,以上只是比較常用的,想知道更多請看navigator 文件

此外,navigator 還有兩個很有趣的 stack 檢查:

  • maybePop:可以 pop 嗎?如果 stack 中還有東西的話就 pop,不然 pop 到空,程式就結束了。
  • canPop:檢查是不是只剩一個起始的 initial screen 了,return false 就是只剩一個,不能再 pop 了。

 

Navigator.push(content, route)
vs.
Navigator.of(content).push(route)

這兩個有什麼不同?答案是一樣的,不過使用 Navigator.of(content) 時有多兩個選擇性的參數:

  • rootNavigator:寫法是 Navigator.of(context, rootNavigator: true).pushNamed("/route"),這是使用在 nested 巢狀 navigator 中,要不要回到 root 的方法,我這樣寫,大家絕對看不懂,這真的很難用文字來說明,還好,網路總有大神,看看這個連結,上面有很棒的圖解,也有程式碼,看完圖後,再回頭看一次我的說明,你就會豁然開朗了。
  • nullOk:設為 true 時,navigator 可以 pop 到 null,也就是程式關閉。

所以,如果你不需要這兩個功能:Navigator.push(...) = Navigator.of(...).pop(...),兩個寫法是一樣的。

 

這個導航方式也不是我們要的,下一種切換網址的方式會更好嗎?讓我們繼續「試」下去吧!


 


WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.


Article info

This article is part of:
Categories:
Total: 1516 words


Share this article:
About the Author

很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯




Join the discussion now!
Don't wait! Sign up to join the discussion.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.