路由在 Flutter 中就像页面导航的“地图”和“导航仪”,负责管理页面之间的跳转、参数传递和堆栈控制。

 一、核心路由类型(基础用法)

1. 基本路由(静态路由:预定义的“固定导航”)

基本路由就是提前在 MaterialApp里列好“页面清单”,给每个页面起一个固定名称(类似网址),后续直接通过名称跳转即可,适合无参数传递的简单页面。

用法示例:

MaterialApp(
  // 路由表:键=路由名称(自定义,通常以/开头),值=对应页面
  routes: {
    '/': (context) => SplashPage(), // 根路由(APP默认启动页)
    '/home': (context) => HomePage(), // 首页
    '/details': (context) => DetailsPage(), // 详情页
  },
  initialRoute: '/', // 指定默认启动的路由(替代home属性)
);

// 跳转方式:直接通过路由名称跳转
Navigator.pushNamed(context, '/home');
// 返回上一页
Navigator.pop(context);

2. 命名路由(动态路由:支持传参的“灵活导航”)

静态路由无法传递参数,而命名路由(通过 `onGenerateRoute` 配置)可以处理动态逻辑,比如给目标页面传数据、做简单拦截,是日常开发的核心用法。

用法示例:

MaterialApp(
  initialRoute: '/',
  // 动态路由生成器:根据路由名称动态匹配页面
  onGenerateRoute: (settings) {
    // settings.name:路由名称
    // settings.arguments:路由携带的参数(任意类型:字符串、对象等)
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(builder: (context) => SplashPage());
      case '/home':
        return MaterialPageRoute(builder: (context) => HomePage());
      // 传递参数:给个人中心页面传用户信息
      case '/profile':
        final userInfo = settings.arguments as Map<String, dynamic>; // 强转类型
        return MaterialPageRoute(
          builder: (context) => ProfilePage(user: userInfo),
        );
      default:
        // 默认匹配不到时返回404页面
        return MaterialPageRoute(builder: (context) => NotFoundPage());
    }
  },
);

// 1. 跳转时携带参数(传递一个用户信息Map)
Navigator.pushNamed(
  context,
  '/profile',
  arguments: {
    'id': 1001,
    'name': '张三',
    'age': 25,
  },
);

// 2. 目标页面(ProfilePage)获取参数
class ProfilePage extends StatelessWidget {
  final Map<String, dynamic> user;
  const ProfilePage({super.key, required this.user});

  @override
  Widget build(BuildContext context) {
    // 也可以通过ModalRoute直接获取(无需构造函数接收)
    final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
    return Scaffold(
      appBar: AppBar(title: Text('${user['name']}的个人中心')),
      body: Text('用户ID:${user['id']},年龄:${user['age']}'),
    );
  }
}

3. 匿名路由(直接导航:临时页面的“快速跳转”)

匿名路由不需要提前在MaterialApp中配置路由表,直接通过 `Navigator.push` 跳转,适合临时打开的页面(比如弹窗式页面、一次性的编辑页面),灵活但无法复用路由名称。

用法示例:

// 直接跳转:无需预配置,传入目标页面即可
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => TemporaryEditPage(), // 临时编辑页面
    fullscreenDialog: true, // 可选:设置为全屏对话框样式(顶部关闭按钮)
  ),
);

// 简化写法(箭头函数)
Navigator.push(context, MaterialPageRoute(builder: (context) => TemporaryEditPage()));

// 返回上一页(和命名路由一致)
Navigator.pop(context);

4. 路由钩子(onUnknownRoute:兜底导航的 “安全网”)

当跳转的路由名称在 routes 静态路由表和 onGenerateRoute 动态路由中都匹配不到时,onUnknownRoute 会触发,用于显示 404 页面或兜底逻辑,避免 APP 崩溃。

用法示例:

MaterialApp(
  routes: {
    '/home': (context) => HomePage(),
  },
  onGenerateRoute: (settings) {
    if (settings.name == '/profile') {
      return MaterialPageRoute(builder: (context) => ProfilePage(user: settings.arguments));
    }
    return null; // 返回null时,会触发onUnknownRoute
  },
  // 兜底路由:所有未匹配的路由都会走这里
  onUnknownRoute: (settings) {
    // 可以打印日志,方便调试
    print('未找到路由:${settings.name},携带参数:${settings.arguments}');
    return MaterialPageRoute(builder: (context) => NotFoundPage());
  },
);

二、路由的核心用途与优势

1. 模块化解耦:降低页面依赖

通过路由名称跳转(比如 Navigator.pushNamed(context, '/home')),不需要在当前页面导入目标页面的组件,减少了组件间的直接依赖,后续修改目标页面时,只要路由名称不变,当前页面无需改动,便于团队协作和代码维护。

2. 参数传递与状态管理:轻松传递复杂数据

支持传递任意类型的数据(字符串、对象、列表等),无需手动维护全局变量,页面间的数据传递更清晰、更安全。

3. 导航堆栈控制:灵活管理页面历史

Flutter 的导航系统基于 “堆栈”(先进后出),提供了丰富的堆栈操作方法,满足各类业务场景:

方法 用途
Navigator.pop(context) 普通返回上一页(弹出栈顶页面)
Navigator.pushReplacement(context, route) 替换当前页面(跳转后无法返回当前页,如登录后替换登录页)
Navigator.popUntil(context, predicate) 回退到指定页面(如从详情页回退到首页,清空中间页面)
Navigator.pushNamedAndRemoveUntil(context, routeName, predicate) 跳转并清空历史堆栈(如退出登录后跳转登录页,禁止返回首页)
Navigator.popUntil(context, ModalRoute.withName('/home')) 示例:回退到首页
Navigator.pushNamedAndRemoveUntil(context, '/login', (route) => false) 示例:跳转登录页并清空所有历史页面

用法示例:

// 1. 替换当前页面(登录成功后,替换登录页为首页)
Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => HomePage()),
);

// 2. 回退到首页
Navigator.popUntil(context, ModalRoute.withName('/home'));

// 3. 跳转登录页并清空所有历史页面
Navigator.pushNamedAndRemoveUntil(
  context,
  '/login',
  (route) => false, // (route) => false 表示清空所有历史页面
);

4. 深度链接与场景适配:支持跨端统一导航

支持通过 URL 直接打开 APP 内的指定页面(比如从微信链接打开 APP 的商品详情页),适配移动端(iOS/Android)和 Web 端的统一导航体验,结合 go_router 第三方库可更便捷地实现复杂深度链接。

5. 过渡动画定制:自定义页面切换效果

默认的页面切换动画是 “左右滑动”,通过 PageRouteBuilder 可以自定义过渡动画(如淡入淡出、缩放、上下滑动等),提升 APP 交互体验。

用法示例:

// 自定义淡入淡出动画
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => NewPage(),
    transitionDuration: Duration(milliseconds: 500), // 动画时长
    reverseTransitionDuration: Duration(milliseconds: 300), // 返回时动画时长
    // 动画构建器
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      // 淡入淡出动画
      return FadeTransition(
        opacity: CurvedAnimation(
          parent: animation,
          curve: Curves.easeInOut, // 动画曲线(缓入缓出)
        ),
        child: child,
      );

      // 可选:缩放动画
      // return ScaleTransition(
      //   scale: animation,
      //   child: child,
      // );

      // 可选:上下滑动动画
      // var begin = Offset(0.0, 1.0);
      // var end = Offset.zero;
      // var tween = Tween(begin: begin, end: end);
      // return SlideTransition(
      //   position: animation.drive(tween),
      //   child: child,
      // );
    },
  ),
);

6. 路由守卫与权限控制:拦截未授权访问

在 onGenerateRoute 中可以实现路由拦截逻辑,比如验证用户是否登录、是否有某个页面的访问权限,未通过验证则跳转至登录页或无权限页面,保障 APP 数据安全。

用法示例:

MaterialApp(
  onGenerateRoute: (settings) {
    // 需要登录才能访问的路由列表
    final needAuthRoutes = ['/profile', '/order', '/mine'];
    // 模拟用户登录状态
    final isLoggedIn = true; // 实际开发中从本地存储或全局状态获取

    // 如果路由需要登录,且用户未登录,则拦截并跳转登录页
    if (needAuthRoutes.contains(settings.name) && !isLoggedIn) {
      return MaterialPageRoute(
        builder: (context) => LoginPage(
          // 登录成功后跳转回原目标页面
          targetRoute: settings.name,
          targetArgs: settings.arguments,
        ),
      );
    }

    // 正常匹配路由
    switch (settings.name) {
      case '/home':
        return MaterialPageRoute(builder: (context) => HomePage());
      case '/profile':
        return MaterialPageRoute(builder: (context) => ProfilePage(user: settings.arguments));
      default:
        return MaterialPageRoute(builder: (context) => NotFoundPage());
    }
  },
);

7. 测试与调试:便于验证页面跳转逻辑

路由名称是明确的跳转目标,在编写集成测试时,可以通过模拟点击跳转按钮,然后验证是否成功跳转到目标页面,便于自动化测试和问题排查。

用法示例:

void main() {
  testWidgets('点击导航按钮跳转到首页', (tester) async {
    // 构建APP
    await tester.pumpWidget(MyApp());

    // 模拟点击跳转按钮(按钮设置Key为nav_to_home)
    await tester.tap(find.byKey(Key('nav_to_home')));
    await tester.pumpAndSettle(); // 等待页面跳转动画完成

    // 验证是否显示首页文本
    expect(find.text('首页'), findsOneWidget);
  });
}

三、补充实用用法

1. 带返回值的路由跳转

有些场景需要从跳转后的页面获取返回值(比如从选择页面返回选中的内容、从编辑页面返回修改后的数据),可以通过 async/await 配合 Navigator.push 实现。

用法示例:

// 发起跳转的页面
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            // 异步获取返回值
            final result = await Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SelectPage()),
            );

            // 处理返回值
            if (result != null) {
              print('从选择页面返回:$result');
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('你选择了:$result')));
            }
          },
          child: Text('打开选择页面'),
        ),
      ),
    );
  }
}

// 目标页面(返回数据)
class SelectPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('选择页面')),
      body: Column(
        children: [
          ListTile(
            title: Text('选项1'),
            onTap: () {
              // 返回数据并关闭当前页面
              Navigator.pop(context, '选项1');
            },
          ),
          ListTile(
            title: Text('选项2'),
            onTap: () {
              Navigator.pop(context, '选项2');
            },
          ),
        ],
      ),
    );
  }
}

3. 路由别名与规范

实际开发中,建议统一管理路由名称(比如创建一个 Routes 类),避免硬编码路由名称导致的拼写错误,便于统一维护和修改。

用法示例:

// 路由名称管理类
class Routes {
  static const String root = '/';
  static const String home = '/home';
  static const String profile = '/profile';
  static const String order = '/order';
  static const String login = '/login';
  static const String notFound = '/404';
}

// 跳转时使用
Navigator.pushNamed(context, Routes.profile);

// 路由配置时使用
MaterialApp(
  onGenerateRoute: (settings) {
    switch (settings.name) {
      case Routes.root:
        return MaterialPageRoute(builder: (context) => SplashPage());
      case Routes.home:
        return MaterialPageRoute(builder: (context) => HomePage());
      // ...
      default:
        return MaterialPageRoute(builder: (context) => NotFoundPage());
    }
  },
);

总结

  1. 路由是 Flutter 页面导航的核心,分为静态路由(简单无参)、动态路由(支持传参 / 拦截)、匿名路由(临时快速跳转),配合 onUnknownRoute 做兜底。
  2. 核心优势:模块化解耦、灵活传参、堆栈控制、支持跨端深度链接、可定制动画、权限拦截。
  3. 实用扩展:带返回值跳转、全局导航 Key、路由名称统一管理,这些用法能大幅提升开发效率和代码质量。
  4. 日常开发中,优先使用 动态路由(onGenerateRoute) + 路由名称统一管理,满足绝大多数业务场景。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐