Flutter Navigator路由相關

一方_發表於2021-08-07

Flutter 路由知識

[TOC]

1. Navigator

Navigator是一個路由管理的元件,它提供了開啟和退出路由頁方法。Navigator通過一個棧來管理活動路由集合。

Flutter分匿名路由與命名路由,比如直接使用Navigator.push就是匿名路由跳轉, 使用Navigator.pushName就是使用命名路由跳轉。

很多跳轉方法只有命名路由才能用, 推薦使用命名路由。

路由表

使用命名路由, 必須要先提供並註冊一個路由表, 這樣應用程式才知道哪個名字與哪個路由元件相對應。其實註冊路由表就是給路由定義個名字, 路由表定義如下:

Map<String, WidgetBuilder> routes;

typedef WidgetBuilder = Widget Function(BuildContext context);
複製程式碼

這是一個Map, key值為路由的名字, 型別是String, value是個builder回撥函式, 用於生成對應的路由widget。

在通過命名路由進行跳轉的時候, 程式會根據路由名字在路由表中查詢到對應的WidgetBuilder回撥函式, 然後呼叫該回撥函式生成路由widget並返回。

路由表的需要在MaterialApp下, 新增routes屬性或者在onGenerateRoute引數中新增。

MaterialApp(
  title: 'Flutter Demo',
  initialRoute:"/", //名為"/"的路由作為應用的home(首頁)
  routes:{//註冊路由表
   'testPage':(context) => TestPage(),
   '/':(context) => HomePage(),
  } ,
);
複製程式碼
命令路由傳遞引數

比如說Navigator.pushNamed(BuildContext context, String routeName, {Object arguments});

引數是arguments, 型別是Object , 一般我們使用的時候都是用Map<String, dynamic>

下面是使用方法

建立一個有引數的頁面:

class ParamPage extends StatelessWidget {
  final int index;
  final List<String> list;
  final TestParam testParam;

  const ParamPage({Key key, this.index, this.list, this.testParam}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('有引數的路由',),),
      body: Center(
        child: OutlinedButton(
          onPressed: (){
            print(index);
            print(list);
            print(testParam.text);
          },
          child: Text('點選'),
        ),
      ),
    );
  }
}

class TestParam{
  int i;
  String text;

  TestParam(this.i, this.text);
}
複製程式碼

在路由表中定義:

MaterialApp(
  title: 'Flutter Demo',
  routes:{//註冊路由表
   'testPage':(context) => TestPage(),
   'paramPage': (context){
   		final Map<String, dynamic> args = ModalRoute.of(context).settings.arguments;
   		return ParamPage(
   			index: args['index'], 
   			list: args['list'], 
   			testParam: args['testParam'],
   		);
   }
  } ,
  home: MyHomePage(title: 'Flutter Demo Home Page'),
);
複製程式碼

也能在MaterialApp的onGenerateRoute引數中定義:

MaterialApp(
  title: 'Flutter Demo',
  onGenerateRoute: (RouteSettings settings) {
  	if(settings.name == 'paramPage'){
  		final Map<String, dynamic> args = settings.arguments as Map<String, dynamic>;
  		return ParamPage(
   			index: args['index'], 
   			list: args['list'], 
   			testParam: args['testParam'],
   		);
  	}
  }
  home: MyHomePage(title: 'DemoPage'),
);
複製程式碼

開啟命名路由頁面, 並傳遞引數:

Navigator.pushNamed(
	context,
	'paramPage',
	arguments: <String, dynamic>{
		'index': 1,
		'list': ['1', '2'],
		'testParam': TestParam(1, 'text'),
	},
);
複製程式碼
路由相關方法

通常當前螢幕顯示的頁面就是棧頂的路由。Navigator提供了一系列方法來管理路由棧,下面整理列出常用的路由跳轉相關方法。

  • push: 跳轉到新頁面。

  • pushNamed: 跳轉到新頁面, 需要路由名。

  • pop: 關閉當前頁面, 返回到上個頁面。

  • canPop: 判斷是否可以導航到新頁面。

  • maybePop: 可能會導航到新頁面 ?( 暫時還不理解這個用法)。

  • pushReplacement: 替換當前路由。

  • pushReplacementNamed: 替換當前路由, 與上面一樣, 需要路由名。

  • popAndPushNamed: 關閉當前頁面, 再跳轉到新頁面。

  • pushAndRemoveUntil: 將給定路由推送到Navigator, 刪除先前路由直至該方法的predicate引數返回true為止。

  • pushNamedAndRemoveUntil: 與上面??那個方法一樣, 只不過替換成了命名路由。

  • popUntil: 反覆執行pop, 直到該方法的predicate引數返回true為止。

使用方法
  1. push

    方法詳情:

    Navigator.push(BuildContext context, Route<T> route);
    複製程式碼

    此方法是將我們需要跳轉的頁面push到棧頂。引數context是上下文, 引數route我們使用MaterialPageRouter 或者 CupertinoPageRoute

    例項使用:

    Navigator.push(context, MaterialPageRoute(builder: (context) => TestRoute2()));
    複製程式碼
  2. pushName

    方法詳情:

    Navigator.pushNamed(
    	BuildContext context, 
    	String routeName, 
    	{Object arguments}
    );
    複製程式碼

    此方法是將我們需要跳轉的頁面push到棧頂。routeName是定義好的路由名稱。

    arguments為需要傳遞的引數。

    例項使用:

    Navigator.pushNamed(context, 'routeName');
    複製程式碼
  3. pushReplacement

    方法詳情:

    Navigator.pushReplacement(
    	BuildContext context, 
    	Route<T> newRoute,
    );
    複製程式碼

    此方法是把當前頁面在棧中的位置替換成要跳轉的路由, 當新頁面進棧顯示後, 之前的頁面將執行dispose方法。

    比如說1->2, 2到3的時候使用了pushReplacement, 在3按返回的時候是回到了1。

    例項使用:

    Navigator.pushReplacement(
    	context, 
    	MaterialPageRoute(builder: (context) => TestRoute3())
    );
    複製程式碼
  4. pushReplacementNamed

    方法詳情:

    Navigator.pushReplacementNamed(
    	BuildContext context, 
    	String routeName, 
    	{Object arguments, Object result}
    );
    複製程式碼

    這個方法與上面??方法一樣, 只不過跳轉的路由換成路由名。

    比如說1-->2, 2到3的時候使用了pushReplacementNamed, 在3按返回的時候是回到了1。

    result為回撥給頁面1的引數, 在跳轉頁面1的方法後面加上.then((value){})就能接收到回撥引數。

    例項使用:

    Navigator.pushReplacementNamed(context, 'routeName');
    複製程式碼
  5. popAndPushNamed

    方法詳情:

    Navigator.popAndPushNamed(
    	BuildContext context, 
    	String routeName, 
    	{Object arguments, Object result}
    );
    複製程式碼

    這個方法與上面??方法一樣, 區別是這個有pop關閉之前頁面的動畫, 關閉了這個頁面再跳轉到新頁面。

    比如說1-->2, 2到3的時候使用了popAndPushNamed, 在3按返回的時候是回到了1。

    result為回撥給頁面1的引數, 在跳轉頁面1的方法後面加上.then((value){})就能接收到回撥引數。

    例項使用:

    Navigator.popAndPushNamed(
    	context, 
    	'routeName',
    );
    複製程式碼
  6. pushAndRemoveUntil

    方法詳情:

    Navigator.pushAndRemoveUntil(
      BuildContext context,
      Route<T> newRoute,
      RoutePredicate predicate,
    );
    複製程式碼

    例如說一個購物支付例子, 可能會有首頁1->挑選商品頁2->填寫訂單3->支付確認頁4->支付成功頁5, 一旦使用者完成了支付事件, 這次訂單支付相關頁面都應該從路由棧中刪除, 在支付成功頁5按返回應該回到首頁1。

    1-->2-->3-->4, 在4進入5時使用pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => TestRoute5()), ModalRoute.withName('testRoute1'));

    這時候如果在頁面5點選返回, 將會回到頁面1。

    例項使用:

    Navigator.pushAndRemoveUntil(
      context,
      MaterialPageRoute(builder: (context) => TestRoute5()),
      ModalRoute.withName('testRoute1'),
    );
    複製程式碼
  7. pushNamedAndRemoveUntil

    方法:

    Navigator.pushNamedAndRemoveUntil(
      BuildContext context,
      String newRoute,
      RoutePredicate predicate,
    );
    複製程式碼

    與上面??方法作用相同, 不同之處是新路由換成了路由名, 路由名需要程式入口指定。

    1-->2-->3-->4, 在4進入5時使用pushNamedAndRemoveUntil

    這時候如果在頁面5點選返回, 將會回到頁面1。

    例項使用:

    Navigator.pushNamedAndRemoveUntil(
      context,
      'testRoute5',
      ModalRoute.withName('testRoute1'),
    );
    複製程式碼
  8. popUntil

    方法詳情:

    Navigator.popUntil(BuildContext context, RoutePredicate predicate);
    複製程式碼

    例如說一個登入註冊, 註冊需要邀請碼的例子, 從首頁1跳轉到登入頁2, 輸入賬號發現賬號未註冊, 然後跳轉到填寫邀請碼頁面3, 在邀請碼頁面3填寫完後需要直接回到首頁, 在進入到邀請碼頁面3時又不能使用pushReplacement方法, 因為邀請碼頁面3還需要返回到登入頁2, 這時候在邀請碼頁面3回到首頁的時候可以使用Navigator.popUntil(context, ModalRoute.withName('testRoute1'));

    這時候會直接回到首頁1

    1-->2-->3, 在頁面3使用popUntil(context, ModalRoute.withName('testRoute1'), 會直接回到首頁1

    例項使用:

    Navigator.popUntil(
      context,
      ModalRoute.withName('testRoute1'),
    );
    複製程式碼

相關文章