路由

显式路由

需要在根组件下手动声明

class MyApp extends StatelessWidget {
    
    Widget build(BuildContext context) {
        return MaterialApp(
            initialRoute: '/', // 默认加载的路由,默认值为 '/'
            routes: {
                // 显式声明路由
                '/': (context) => RootPage(),
                '/A': (context) => Apage(),
                '/B': (context) => Bpage(),
                '/C': (context) => Cpage(),
            },
            // home: RootPage(),
        );
    }
}

注意:'/': (context) => RootPage()home: RootPage() 不能同时存在

静态路由跳转

方法名中带 Name 的大多数是通过静态路由完成跳转的

Navigator.of(context).pushNamed('/A');
Navigator.of(context).pushReplacementNamed('/A');
Navigator.of(context).pushNamedAndRemoveUntil('/A');

动态路由跳转

动态路由可随时使用,无需在根组件的 routes 中注册

Navigator.of(context).push(MaterialPageRoute(
    builder: (context) => Apage(),
));

动态路由需要传入一个 Route,示例中使用的是 MaterialPageRoute,它可以使用和平台风格一致的路由切换动画(iOS 左右,Android 上下),也可使用 CupertinoPageRoute 实现全平台的左右滑动,使用 PageRouteBuilder 可自定义动画

Navigator.of(context).push(
    PageRouteBuilder(
        transitionDuration: Duration(milliseconds: 250), // 动画时长 250 毫秒
        pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) {
            // 渐隐渐入过渡动画
            return FadeTransition(
                opacity: animation,
                child: Apage(),
            );
        }
    )
)

相关方法说明

pop

返回当前路由栈的上一个界面

Navigator.pop(context)

push / pushNamed

基础路由跳转,将一个 page 压入路由栈中,在原来的路由栈上添加一个新的 page

Navigator.of(context).pushNamed('/A');

Navigator.of(context).push(MaterialPageRoute(
    builder: (context) => Apage(),
))

pushReplacement / pushReplacementNamed / popAndPushNamed

替换路由跳转,将当前路由替换掉再跳转(即当前路由不会出现在路由栈中)。popAndPushNamed 的动画效果不一样

Navigator.of(context).pushReplacementNamed('/A');

Navigator.of(context).pushReplacement(MaterialPageRoute(
    builder: (context) => Apage(),
))

Navigator.of(context).popAndPushNamed('/A');

pushAndRemoveUntil / pushNamedAndRemoveUntil

按次序移除其他的路由,直到遇到被标记的路由(predicate 函数返回了 true)时停止

  • 根据 predicate 的返回值决定新路由之前的路由的处理方式
    • true:保持不变
    • false:则新路由外的所有路由都删掉
  • 若没有标记的路由,则全部移除
  • 当存在重复的标记时,默认移除到最近的一个时停止

移除全部

// 第一种
Navigator.pushAndRemoveUntil(
    context,
    MaterialPageRoute(builder: (_) => Cpage()),
    (Route route) => route == null
);

// 第二种
Navigator.of(context).pushNamedAndRemoveUntil(
    '/C',
    (Route route) => route == null
);

移除到 RootPage 停止

// 第一种
Navigator.pushAndRemoveUntil(
    context,
    MaterialPageRoute(builder: (_) => Cpage()),
    ModalRoute.withName('/')
);
// 仅写法不同
Navigator.pushAndRemoveUntil(
    context,
    MaterialPageRoute(builder: (_) => Cpage()),
    (Route route) => route.settings.name == '/'
);


// 第二种
Navigator.of(context).pushNamedAndRemoveUntil(
    '/C',
    (Route route) => route.settings.name == '/'
);
// 仅写法不同
Navigator.of(context).pushNamedAndRemoveUntil(
    '/C',
    ModalRoute.withName('/')
);

popUntil

返回到指定的标记路由,若标记的路由为 null,则程序退出

Navigator.of(context).popUntil((route) => route.settings.name == '/');

Navigator.of(context).popUntil(ModalRoute.withName('/'));

// 返回根路由
Navigator.of(context).popUntil((route) => route.isFirst);

若标记的路由为动态路由,可在跳转到标记路由的时候设置一下,这样在返回时即可直接调用。示例如下

// 设置 Apage 的 RouteSettings
Navigator.of(context).push(MaterialPageRoute(
    settings: RouteSettings(name: '/A'),
    builder: (context) => Apage(),
))

// 在 Cpage 需要返回时调用即可
Navigator.of(context).popUntil(ModalRoute.withName('/A'));

canPop

判断是否可以导航到新页面,返回 bool 类型,通常是在设备带返回的物理按键时需要判断是否可以 pop

Navigator.of(context).canPop();

maybePop

canPop 的升级版本,如果当前路由可弹出则自动执行,否则不执行

removeRoute / removeRouteBelow

删除路由,同时执行 Route.dispose 操作,无过渡动画,正在进行的手势也会被取消。removeRouteBelow 删除指定路由下面的第一个路由,当对应的路由不存在时会报错

Navigator.of(context).removeRoute(route);

Navigator.of(context).removeRouteBelow(currentRoute, predicate);

路由传值

向下级路由传值

  • 构造函数传值

个人感觉比较麻烦

// 构造一个可以带参数的构造函数
class Apage extends StatefulWidget {
    String title;
    Apage(this.title);

    
    ApageState createState() => ApageState();

    
    Widget build(BuildContext context) {
        return Container(
            child: Text(widget.title) // 使用 'widget.参数名' 获取
        )
    }
}

Navigator.of(context).push(MaterialPageRoute(
    builder: (context) => Apage('这是传入的参数'),
))
  • ModalRoute 传值
Navigatro.of(context).push(MaterialPageRoute(
    settings: RouteSettings(name: '/A', arguments: {'argms': '这是传入的参数'}),
    builder: (context) => Apage(),
))
// 或
Navigator.of(context).pushNamed('/A', arguments: {'argms': '这是传入的参数'});

// 在 Apage 中取值
class Apage extends StatelessWidget {
    
    Widget build(BuildContext context) {
        final params = ModalRoute.of(context).settings.arguments
        return Container(
            // ...
        )
    }
}

返回上级路由时传值

Navigator.of(context).pop('这是pop返回的参数');

// 在上一级路由获取
final result = await Navigator.of(context).push(MaterialPageRoute(
    builder: (context) => Cpage()
))
// 或
String value = await Navigator.of(context).pushNamed('/C');
Last Updated:
Contributors: af