Flutter路由(Navigator)的使用和详解

456 阅读5分钟

Flutter路由(Navigator)的使用

Push类型方法将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据

Push方法:

  /**
    * 在栈顶入栈一个新的路由
    * route 路由页面
    */
   push(Route route) 
   
    /**
     * 将当前路由替换为一个新的路由
     * newRoute 同上route
     * result 可选参数result表示的是这个页面的返回结果,如果设置的话,会返回给被替换的这个页面的前一个页面
    */
   pushReplacement(Route newRoute, { TO? result }) 
   
   /**
    * 跳转到指定页面,并按顺序(从栈顶到栈底)移出之前的所有页面,直到predicate返回true。
    * newRoute 同上route
    * predicate 类型RoutePredicate = bool Function(Route<dynamic> route)
    * route获取路由信息路由信息,确定移除指定路由返回true。返回false,移出之前的所有页面。
    */
   pushAndRemoveUntil(Route newRoute, RoutePredicate predicate) 

Route分为了页面路由(PageRoute)和窗口路由(PopupRoute)。PopupRoute的默认实现均为私有,要用到的话需要我们自己去实现。PageRoute默认提供了三个公开的实现类:

  • CupertinoPageRoute:Cupertino风格的默认实现。
  • MaterialPageRoute:Material风格的默认实现。
  • PageRouteBuilder:自定义PageRoute,比如一些动画效果。

PageRouteBuilder 使用

/**
  * settings 包含路由的配置信息,如路由名称、是否初始路由
  * pageBuilder 用来构建路由的主要内容
  * transitionsBuilder 用于构建路由的变换效果
  * transitionDuration 变换效果的持续时间
  * opaque 是否不透明,默认为true,如果是不透明的话,路由变换完成之后,不会再构建位于该路由之下的路由,以节省资源
  * barrierDismissible 点击屏障是否自动消失。 
  * barrierColor 模态屏障的颜色。如果为null,则屏障将是透明的。比如弹出一个对话框时,背景可以设置成灰暗的。注意Dialog也是一个路由。
  * barrierLabel
  * maintainState 默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置`maintainState`为 `false`
  */
  PageRouteBuilder({
    RouteSettings settings,
    @required this.pageBuilder,
    this.transitionsBuilder = _defaultTransitionsBuilder,
    this.transitionDuration = const Duration(milliseconds: 300),
    this.opaque = true,
    this.barrierDismissible = false,
    this.barrierColor,
    this.barrierLabel,
    this.maintainState = true,
  }) : assert(pageBuilder != null),
       assert(transitionsBuilder != null),
       assert(barrierDismissible != null),
       assert(maintainState != null),
       assert(opaque != null),
       super(settings: settings);
       
例如:

PageRouteBuilder(
    transitionDuration: Duration(milliseconds: 500), //动画时间为500毫秒
    pageBuilder: (BuildContext context, Animation animation,
        Animation secondaryAnimation) {
      return FadeTransition(
        //使用渐隐渐入过渡,
        opacity: animation,
        child: PageB(), //路由B
      );
    },
  )

PushName方法

    /**
    * 在栈顶入栈一个新的路由
    * routeName 路由名字
    * arguments 传递的参数
    */
   pushNamed(String routeName, { Object? arguments}) 
   
  /**
    * 将当前路由替换为一个新的路由 
    * routeName 同上routeName 
    * result 可选参数result表示的是这个页面的返回结果,如果设置的话,会返回给被替换的这个页面的前一个页面 
    * arguments 传递的参数
    */
   pushReplacementNamed( String routeName, {TO? result,
    Object? arguments}) 
    
    /**
    * 跳转到指定页面,并按顺序(从栈顶到栈底)移出之前的所有页面,直到predicate返回true。
    * newRouteName 同上route
    * predicate 类型RoutePredicate = bool Function(Route<dynamic> route)
    * route获取路由信息路由信息,确定移除指定路由返回true。返回false,移出之前的所有页面。
    * arguments  传递的参数
    */
   pushNamedAndRemoveUntil( String newRouteName,
    RoutePredicate predicate, {
    Object? arguments,
  }) 

注意: 使用命名路由跳转,首先需要将路由进行注册

  class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Good'),
      routes: {
        "mainPage": (context) => MainPage(),
        "loginPage": (context) => LoginPage()
      },
    );
  }
}

获取传递的数据

路由跳转新界面使用arguments传递数据或者使用PageRouteBuilder中的settings传递数据。 使用 ModalRoute.of(context).settings.arguments 获取数据。

路由拦截器(路由钩子)

通过onGenerateRoute做一些全局的路由跳转前置处理逻辑。在MaterialApp中使用onGenerateRoute参数设置拦截器。 代码:

MaterialApp(
  ... //省略无关代码
  onGenerateRoute:(RouteSettings settings){
	  return MaterialPageRoute(builder: (context){
		   String routeName = settings.name;
       // 如果访问的路由页需要登录,但当前未登录,则直接返回登录页路由,
       // 引导用户登录;其他情况则正常打开路由。
     }
   );
  }
);

pop方法

 /**
   * 当前路由出栈
   * result 可选参数,返回数据
   */
  pop([ T result ]) 
  
  /**
   * 当前路由出栈,入栈一个新路由
   * routeName 同上routeName 
   * result 可选参数result表示的是这个页面的返回结果,如果设置的话,会返回给被替换的这个页面的前一个页面 
   * arguments 传递的参数
   */
  popAndPushNamed(String routeName, {
    TO? result,
    Object? arguments})
    
  /**
   * 从栈顶开始,逐个pop,直到参数中指定的路由为止
   * result 可选参数,返回数据
   */
   popUntil 
   
   /**
    * 判断当前路由是否可以出栈,如果栈内只有当前路由,返回false,如果当前路由前面还有路由,返回true。也就是说栈底的路由,该方法返回false
    */
   canPop(BuildContext context)
   
   /**
    * 当前路由如能能出栈就出栈,如果不能就什么都不做。
    * 是pop的安全返回方式.参数作用于pop的一样
    * result 可选参数,返回数据
    */
   maybePop(BuildContext context, [ T result ])

remove方法

  /**
    *删除一个指定的路由,如果该路由存在于栈内正常删除,否则报错,例如:路由顺序A-B-C-D,remove C,结果路由顺序是A-B-D
    *route 需要移除的路由
    */
   removeRoute(BuildContext context, Route route)
   
  /**
    *给定一个路由,在路由表内删除其前一个路由。例如:路由顺序A-B-C-D,remove C,结果路由顺序是A-C-D
    *anchorRoute 需要移除的路由
    */
   removeRouteBelow(BuildContext context, Route anchorRoute)

replace方法

  /**
    * 用一个新的路由,将路由表内的一个已存在的路由替换掉
    * oldRoute 需要替换的路由
    * newRoute 新路由
    */
   replace(BuildContext context, { @required Route oldRoute, @required Route newRoute })
   
   /**
    * 用一个新的路由,将路由表内的一个已存在的路由的前面的路由给替换掉
    * anchorRoute 需要替换的后一个路由
    * newRoute 新路由
    */
   replaceRouteBelow(BuildContext context, { @required Route anchorRoute, Route newRoute })