Flutter頁面跳轉(zhuǎn)總結(jié)

前言

Flutter(本文用的flutter是1.9.1版本)和許多其他移動應(yīng)用一樣也是使用棧來管理頁面的敛摘,進入一個新頁面就是一個入棧操作门烂,而退出一個頁面時就是一個出棧操作。

在Flutter中一個頁面就是一個Route對象兄淫,而管理這里Route對象的就是Navigator,例如Navigator.push負(fù)責(zé)入棧Route對象慨丐,Navigator.pop負(fù)責(zé)出棧Route對象。

頁面跳轉(zhuǎn)相關(guān)API介紹

一泄私、跳轉(zhuǎn)到新頁面

相關(guān)方法

  1. Future<T> push<T extends Object>(Route<T> route)
  2. Future<T> pushNamed<T extends Object>(String routeName, {Object arguments, })

先看個例子(從Page1跳轉(zhuǎn)到Page2):

Navigator.of(context).push(MaterialPageRoute(builder: (context) => Page2()));
或:
Navigator.of(context).pushNamed("/page2");

首先房揭,對于Navigator的使用,從上面例子中可以看出是通過Navigator.of(context)獲取到當(dāng)前的NavigatorState對象(of方法返回的是一個NavigatorState對象)晌端,然后調(diào)用對應(yīng)的push方法或pushNamed方法。

這里也可以省略of方法蓬痒,直接將context參數(shù)寫到pushpushNamed方法中漆羔,如Navigator.pushNamed(context, "/page2");本質(zhì)上是一樣的,來看看源碼:

static Future<T> pushNamed<T extends Object>(
    BuildContext context,
    String routeName, {
    Object arguments,
   }) {
    return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
 }

可見演痒,最終也是先調(diào)用Navigator.of(context)方法來獲取到當(dāng)前的NavigatorState對象,然后在調(diào)用對應(yīng)的方法鸟顺。

匿名路由

對于push方法,前面我們說了Navigator管理的Route對象蹦锋,而一個頁面就是一個Route,而且通過上面的API也可以看出晕粪,push的第一個參數(shù)是一個Route對象渐裸,因此這里我們需要將要跳轉(zhuǎn)的頁面包裝成一個Route對象傳給Navigator。這里我們用的是MaterialPageRoute尚氛,一個帶有Material風(fēng)格的路由(比如實現(xiàn)了一些Material風(fēng)格的跳轉(zhuǎn)動畫效果等)洞渤。另外還有IOS風(fēng)格的路由CupertinoPageRoute。如果想要實現(xiàn)自定義效果载迄,可以使用PageRouteBuilder去加自己想要的效果。

命名路由

pushNamed方法我們只傳了一個字符串魂迄,這里又是這么生成Route對象的吶惋耙?這就是Flutter路由的另外一個使用方式了。要直接使用名字做跳轉(zhuǎn)需要我們先對路由進行命名:

void main() {
  runApp(MaterialApp(
    home: MyAppHome(), // becomes the route named '/'
    routes: <String, WidgetBuilder> {
      '/page1': (context) => Page1(),
      '/page2': (context) => Page2(),
      '/page3': (context) => Page3(),
    },
  ));
}

然后在頁面跳轉(zhuǎn)的時候我們只需要使用pushNamed傳遞一個路由名字即可完成跳轉(zhuǎn)湿酸,系統(tǒng)會使用名字和對應(yīng)的路由構(gòu)造器自動為我們創(chuàng)建一個Route灭美。

注意:

  1. 對于home指定的頁面推溃,系統(tǒng)會自動命名為/冲粤;
  2. 這里的名字是可以重復(fù)的美莫,每個名字對應(yīng)的頁面也不是唯一的梯捕,所以這里是多對多的情況。比如home指定的參數(shù)是page1:home: Page1();襟铭,下面又添加了一個page1:'/page1': (ontext) => Page1(),當(dāng)程序啟動后(沒做跳轉(zhuǎn))寒砖,路由歷史棧里面Page1對應(yīng)的名字是/而不是/page1

所以魁兼,這兩個方法的區(qū)別就是:使用push進行頁面跳轉(zhuǎn)的時候我們不用提前進行命名漠嵌,但是每次跳轉(zhuǎn)的時候需要手動創(chuàng)建一個Route,而使用pushNamed進行頁面跳轉(zhuǎn)的時候只需要一個名字即可儒鹿,但是需要提前命名。

另外植阴,按照上面例子中的寫法圾浅,push跳轉(zhuǎn)時生成的Route是沒有名字的(是null),如需指定名字贱傀,可以這樣寫:

 Navigator.of(context).push(MaterialPageRoute(
       builder: (context) => Page2(),
       settings: RouteSettings(name: "/page2"),
 ));

即在創(chuàng)建Route的時候除了指定builder參數(shù)之外府寒,還可以傳遞一個settings,在settings中去指定名字株搔。

參數(shù)傳遞

通過前面方法的簽名我們看到pushNamed有兩個參數(shù),第二個是一個Object arguments纵隔,這個就是用來傳遞參數(shù)的炮姨,類型是Object,也就是說我們可以傳遞任意類型的參數(shù)舒岸。對于push方法需要傳遞參數(shù)的話有兩種方式,第一種是在頁面的構(gòu)造函數(shù)中傳遞俄认,如:

Navigator.of(context).push(MaterialPageRoute(builder: (context) => Page2(title: "hello")));

另外一種方式是通過前面提到過的settings參數(shù)來傳遞,如:

 Navigator.of(context).push(MaterialPageRoute(
       builder: (context) => Page2(),
       settings: RouteSettings(name: "/page2", arguments: {"title": "hello"}),
 ));

這里的arguments同樣是一個Object眯杏,也就是可以指定任意的參數(shù)類型。pushNamed最終也是將名字和參數(shù)封裝到settings中的茫经。

在新頁面中萎津,通過以下方式取出傳遞的參數(shù):

@override
  Widget build(BuildContext context) {
    Object arguments = ModalRoute.of(context).settings.arguments;
    // TODO
  }

接收返回值

通過前面可以看到,pushpushNamed的返回值類型是一個Future<T>姜性,這個就是前一個頁面的返回值髓考,如:

Navigator.of(context).pushNamed("/page2").then((value){
    // 這里處理返回值 
    print("return value=$value");
 })

至于上一個頁面如何設(shè)置返回值后面講解pop方法的時候再說氨菇。

二、退出當(dāng)前頁面并跳轉(zhuǎn)到新頁面

  1. Future<T> pushReplacement<T extends Object, TO extends Object>(Route<T> newRoute, { TO result })
  2. Future<T> pushReplacementNamed<T extends Object, TO extends Object>(String routeName, {TO result, Object arguments, })
  3. Future<T> popAndPushNamed<T extends Object, TO extends Object>(String routeName, {TO result, Object arguments, })

這三個方法的功能都是退出當(dāng)前頁面并進入新的頁面查蓉。1和2的區(qū)別就不說了,和前面一樣妹田。12和3的區(qū)別是:12兩個方法都是先進入新的頁面鹃共,然后再退出當(dāng)前頁面,也就是當(dāng)前頁面的退出動畫是看不見的霜浴;方法3是先退出當(dāng)前頁面,然后在進入新的頁面晌纫,也就是當(dāng)前頁面的退出動畫是看得見的永丝。

三、清除歷史頁面并跳轉(zhuǎn)到新頁面

  1. Future<T> pushNamedAndRemoveUntil<T extends Object>(String newRouteName, RoutePredicate predicate, {Object arguments, })
  2. Future<T> pushAndRemoveUntil<T extends Object>(Route<T> newRoute, RoutePredicate predicate)

這里重點是第二個參數(shù)predicate类溢。在跳轉(zhuǎn)新頁面的時候會對當(dāng)前歷史棧里的頁面依次進行遍歷露懒,然后通過predicate回調(diào)給用戶進行處理砂心,如果predicate返回false就表示這個頁面需要退出辩诞,直到歷史遍歷完或者predicate返回true為止坎弯。

比如:

// 這里第二個參數(shù)始終返回false译暂,則會清除所有歷史頁面,該方法執(zhí)行完成后只會存在page2一個頁面
Navigator.of(context).pushNamedAndRemoveUntil("/page2", (route) => false);

// 清除/page2之上的所有頁面
Navigator.of(context).pushNamedAndRemoveUntil("/page4", (route) {
     return route.settings.name == "/page2";
 });

// 清除除了根頁面之外的所有歷史頁面
Navigator.of(context).pushNamedAndRemoveUntil("/page2", ModalRoute.withName("/"));

這里的ModalRoute.withName主要也是對名字進行判斷:

static RoutePredicate withName(String name) {
    return (Route<dynamic> route) {
      return !route.willHandlePopInternally
          && route is ModalRoute
          && route.settings.name == name; // 判斷名字是否是指定的名字
    };
  }

四崎脉、退出當(dāng)前頁面

  1. bool pop<T extends Object>([ T result ]):退出當(dāng)前頁面伯顶,result為要返回的參數(shù);
  2. void popUntil(RoutePredicate predicate):退出歷史棧中的頁面灶体,直到predicate返回true掐暮;

另外還有兩個方法:

  1. bool canPop():檢查當(dāng)前頁面是否可以返回;
  2. Future<bool> maybePop<T extends Object>([ T result ]) async:嘗試進行返回(不一定成功)樟结;

自定義路由

這里給個簡單的自定義實現(xiàn):

  Navigator.of(context).push(
    PageRouteBuilder(
      transitionDuration: Duration(milliseconds: 300), 
      pageBuilder: (context, animation, secondaryAnimation) {
        return FadeTransition(
          opacity: animation,
          child: Page2(),
        );
      },
    ),
  );

具體請見官方文檔Custom routes部分精算。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市殖妇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疲吸,老刑警劉巖前鹅,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蹂喻,居然都是意外死亡,警方通過查閱死者的電腦和手機口四,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門蔓彩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赤嚼,你說我怎么就攤上這事〉确酰” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵流济,是天一觀的道長腌闯。 經(jīng)常有香客問我雕憔,道長,這世上最難降的妖魔是什么分瘦? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任琉苇,我火速辦了婚禮,結(jié)果婚禮上并扇,老公的妹妹穿的比我還像新娘。我一直安慰自己土陪,他們只是感情好肴熏,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著源哩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪励烦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天漆魔,我揣著相機與錄音却音,去河邊找鬼。 笑死系瓢,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的欠拾。 我是一名探鬼主播骗绕,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酬土!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刹枉,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤屈呕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蟋软,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡钟鸵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年棺耍,在試婚紗的時候發(fā)現(xiàn)自己被綠了种樱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俊卤。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡害幅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出以现,到底是詐尸還是另有隱情,我是刑警寧澤佣赖,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布记盒,位于F島的核電站,受9級特大地震影響纪吮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棚辽,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一冰肴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嚼沿,春花似錦瓷患、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谭贪。三九已至锦担,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間套媚,已是汗流浹背缚态。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工玫芦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留本辐,地道東北人桥帆。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓老虫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親张遭。 傳聞我的和親對象是個殘疾皇子地梨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345