Flutter Navigator路由相关

1,256 阅读6分钟

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'),
    );