Flutter 的导航系统分为 Navigator 1.0(命令式)和 Navigator 2.0(声明式)两代。理解两者的差异有助于选择合适的导航方案。


一、Navigator 1.0(命令式导航)

Navigator 1.0 是传统的命令式导航,通过 push/pop 操作路由栈。

1.1 基本导航操作

// push:压栈(进入新页面)
Navigator.push(
  context,
  MaterialPageRoute(builder: (_) => const DetailPage()),
);

// pop:出栈(返回上一页)
Navigator.pop(context);

// pop 并传递返回值
Navigator.pop(context, 'result_data');

// 接收返回值
final result = await Navigator.push<String>(
  context,
  MaterialPageRoute(builder: (_) => const EditPage()),
);
print('Returned: $result');

// pushReplacement:替换当前页面(不可返回)
Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (_) => const HomePage()),
);

// pushAndRemoveUntil:清空路由栈跳转
Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (_) => const LoginPage()),
  (route) => false, // false = 清空所有
);

// popUntil:返回到指定路由
Navigator.popUntil(context, ModalRoute.withName('/home'));

1.2 命名路由(pushNamed)

// 注册路由表
MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => const HomePage(),
    '/product': (context) => const ProductPage(),
    '/login': (context) => const LoginPage(),
    '/profile': (context) => const ProfilePage(),
  },
)

// 使用命名路由导航
Navigator.pushNamed(context, '/product');

// 传递参数
Navigator.pushNamed(
  context,
  '/product',
  arguments: {'productId': 123, 'from': 'home'},
);

// 在目标页面接收参数
class ProductPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final args = ModalRoute.of(context)!.settings.arguments
        as Map<String, dynamic>;
    final productId = args['productId'] as int;
    return Text('Product $productId');
  }
}

1.3 onGenerateRoute(动态路由生成)

MaterialApp(
  onGenerateRoute: (settings) {
    // 解析路由路径,支持动态参数
    final uri = Uri.parse(settings.name ?? '/');

    switch (uri.pathSegments.first) {
      case 'product':
        final id = int.tryParse(uri.pathSegments.last);
        return MaterialPageRoute(
          builder: (_) => ProductDetailPage(productId: id!),
          settings: settings,
        );

      case 'category':
        final slug = uri.pathSegments.last;
        return MaterialPageRoute(
          builder: (_) => CategoryPage(slug: slug),
        );

      default:
        return MaterialPageRoute(builder: (_) => const NotFoundPage());
    }
  },
  onUnknownRoute: (settings) => MaterialPageRoute(
    builder: (_) => const NotFoundPage(),
  ),
)

二、Navigator 2.0(声明式导航)

Navigator 2.0 将路由变成了"状态",通过声明式方式描述路由栈,更适合 Web 端的 URL 管理和深链。

2.1 RouterDelegate

class AppRouterDelegate extends RouterDelegate<AppRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoutePath> {

  
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  AppRoutePath _currentPath = AppRoutePath.home();

  // 当前路由状态
  AppRoutePath get currentPath => _currentPath;

  void navigateTo(AppRoutePath path) {
    _currentPath = path;
    notifyListeners(); // 通知导航系统重建路由栈
  }

  
  AppRoutePath get currentConfiguration => _currentPath;

  
  Widget build(BuildContext context) {
    // 声明式:根据状态描述路由栈
    return Navigator(
      key: navigatorKey,
      pages: [
        const MaterialPage(key: ValueKey('home'), child: HomePage()),
        if (_currentPath.isProduct)
          MaterialPage(
            key: ValueKey('product_${_currentPath.productId}'),
            child: ProductDetailPage(productId: _currentPath.productId!),
          ),
      ],
      onPopPage: (route, result) {
        if (!route.didPop(result)) return false;
        navigateTo(AppRoutePath.home());
        return true;
      },
    );
  }

  
  Future<void> setNewRoutePath(AppRoutePath path) async {
    _currentPath = path;
  }
}

2.2 RouteInformationParser

class AppRouteInformationParser extends RouteInformationParser<AppRoutePath> {
  
  Future<AppRoutePath> parseRouteInformation(RouteInformation info) async {
    final uri = Uri.parse(info.location ?? '/');

    if (uri.pathSegments.isEmpty) return AppRoutePath.home();
    if (uri.pathSegments.first == 'product' && uri.pathSegments.length == 2) {
      return AppRoutePath.product(int.parse(uri.pathSegments[1]));
    }
    return AppRoutePath.unknown();
  }

  
  RouteInformation? restoreRouteInformation(AppRoutePath path) {
    if (path.isHome) return const RouteInformation(location: '/');
    if (path.isProduct) return RouteInformation(location: '/product/${path.productId}');
    return const RouteInformation(location: '/404');
  }
}

三、MaterialPageRoute 与自定义 Route

3.1 MaterialPageRoute

// 标准 Material 风格过渡(Android:底部滑入;iOS:右侧滑入)
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => const DetailPage(),
    fullscreenDialog: true, // iOS 全屏模态样式(从底部滑入)
    maintainState: false,   // 返回时是否保留状态
  ),
)

3.2 CupertinoPageRoute

// iOS 风格过渡(右侧滑入,支持边缘滑动返回)
Navigator.push(
  context,
  CupertinoPageRoute(builder: (_) => const DetailPage()),
)

3.3 自定义过渡动画

class FadeScaleRoute<T> extends PageRouteBuilder<T> {
  final Widget page;

  FadeScaleRoute({required this.page})
      : super(
          pageBuilder: (_, __, ___) => page,
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            return FadeTransition(
              opacity: animation,
              child: ScaleTransition(
                scale: Tween<double>(begin: 0.9, end: 1.0).animate(
                  CurvedAnimation(parent: animation, curve: Curves.easeOut),
                ),
                child: child,
              ),
            );
          },
          transitionDuration: const Duration(milliseconds: 250),
          reverseTransitionDuration: const Duration(milliseconds: 200),
        );
}

四、路由栈管理

4.1 路由栈常用操作

操作方法场景
入栈push进入新页面,可返回
出栈pop返回上一页
替换pushReplacement登录成功后替换登录页
清空入栈pushAndRemoveUntil退出登录后清空栈
出栈到指定popUntil多级返回到主页
查看栈顶canPop()判断是否可以返回

4.2 嵌套 Navigator

class MainPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          NavigationPanel(),
          Expanded(
            child: Navigator( // 嵌套的 Navigator,用于右侧内容区
              initialRoute: 'dashboard',
              onGenerateRoute: (settings) {
                return MaterialPageRoute(
                  builder: (_) => switch (settings.name) {
                    'dashboard' => const DashboardPage(),
                    'settings' => const SettingsPage(),
                    _ => const NotFoundPage(),
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

小结

特性Navigator 1.0Navigator 2.0
编程范式命令式声明式
适用场景普通移动 AppWeb / 深链 / 复杂路由
学习成本
URL 支持有限完整
第三方支持GoRouter / AutoRouteGoRouter(推荐)

👉 下一节:4.2 命名路由与参数传递

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐