Flutter GoRouter + Riverpod 增强版ShellRoute 特性—混合路由导航方案

· 在 ShellRoute 内部:自动有底部导航

· 在 ShellRoute 外部:自动没有底部导航

🎯 方案特点

· ✅ 简洁明了:最小化代码,最大化效果

· ✅ 开箱即用:复制即运行

· ✅ 易于扩展:添加页面只需1分钟

· ✅ 状态管理:Riverpod 提供响应式状态

📁 项目结构

复制代码
lib/
├── main.dart          # 应用入口
├── app.dart          # 应用配置
├── router.dart       # 路由配置(核心文件)
├── bottom_nav.dart   # 底部导航组件
└── pages/           # 页面目录
    ├── home_page.dart
    ├── category_page.dart
    ├── login_page.dart
    └── product_page.dart
  1. 核心文件:router.dart
dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'pages/home_page.dart';
import 'pages/category_page.dart';
import 'pages/login_page.dart';
import 'pages/product_page.dart';
import 'bottom_nav.dart';

// 当前标签页索引
final tabIndexProvider = StateProvider<int>((ref) => 0);

// 路由配置
final routerProvider = Provider<GoRouter>((ref) {
  return GoRouter(
    initialLocation: '/',
    routes: [
      // ShellRoute:底部导航页面组
      ShellRoute(
        builder: (context, state, child) {
          final index = ref.watch(tabIndexProvider);
          return Scaffold(
            body: child,
            bottomNavigationBar: BottomNav(
              currentIndex: index,
              onTabSelected: (i) {
                ref.read(tabIndexProvider.notifier).state = i;
                _goToTab(i, context);
              },
            ),
          );
        },
        routes: _buildTabRoutes(),
      ),
      
      // 独立页面:无底部导航
      ..._buildIndependentRoutes(),
    ],
  );
});

// 标签页路由
List<GoRoute> _buildTabRoutes() => [
  GoRoute(path: '/', builder: (_, __) => const HomePage()),
  GoRoute(path: '/category', builder: (_, __) => const CategoryPage()),
];

// 独立页面路由
List<GoRoute> _buildIndependentRoutes() => [
  GoRoute(
    path: '/login',
    builder: (_, __) => const LoginPage(),
  ),
  GoRoute(
    path: '/product/:id',
    builder: (_, state) {
      final id = state.pathParameters['id']!;
      return ProductPage(id: id);
    },
  ),
];

// 标签页跳转
void _goToTab(int index, BuildContext context) {
  switch (index) {
    case 0: context.go('/'); break;
    case 1: context.go('/category'); break;
  }
}
  1. 底部导航组件:bottom_nav.dart
dart 复制代码
import 'package:flutter/material.dart';

class BottomNav extends StatelessWidget {
  final int currentIndex;
  final Function(int) onTabSelected;

  const BottomNav({
    super.key,
    required this.currentIndex,
    required this.onTabSelected,
  });

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      currentIndex: currentIndex,
      onTap: onTabSelected,
      items: const [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: '首页',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.category),
          label: '分类',
        ),
      ],
    );
  }
}
  1. 应用配置:app.dart
dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'router.dart';

class App extends ConsumerWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final router = ref.watch(routerProvider);
    
    return MaterialApp.router(
      routerConfig: router,
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
    );
  }
}
  1. 应用入口:main.dart
dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'app.dart';

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const App();
  }
}
  1. 页面示例

首页(有底部导航)

dart 复制代码
// pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('首页')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('这是有底部导航的页面'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => context.go('/product/123'),
              child: const Text('查看商品'),
            ),
            ElevatedButton(
              onPressed: () => context.go('/login'),
              child: const Text('去登录'),
            ),
          ],
        ),
      ),
    );
  }
}

分类页(有底部导航)

dart 复制代码
// pages/category_page.dart
import 'package:flutter/material.dart';

class CategoryPage extends StatelessWidget {
  const CategoryPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(title: Text('分类')),
      body: Center(child: Text('分类页面')),
    );
  }
}

登录页(无底部导航)

dart 复制代码
// pages/login_page.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('登录'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () {
            if (context.canPop()) context.pop();
            else context.go('/');
          },
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('这是没有底部导航的页面'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => context.go('/'),
              child: const Text('登录成功,返回首页'),
            ),
          ],
        ),
      ),
    );
  }
}

商品页(无底部导航)

dart 复制代码
// pages/product_page.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class ProductPage extends StatelessWidget {
  final String id;

  const ProductPage({super.key, required this.id});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('商品 $id'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => context.pop(),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('商品ID: $id'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => context.go('/'),
              child: const Text('返回首页'),
            ),
          ],
        ),
      ),
    );
  }
}

🚀 快速开始

步骤 1:创建项目

bash 复制代码
flutter create myapp
cd myapp

步骤 2:添加依赖

bash 复制代码
flutter pub add go_router flutter_riverpod

步骤 3:替换文件

将上面的代码复制到对应的文件中。

步骤 4:运行项目

bash 复制代码
flutter run

🔧 扩展说明

添加新的底部导航页面

dart 复制代码
// 1. 在 _buildTabRoutes() 中添加路由
GoRoute(path: '/cart', builder: (_, __) => const CartPage()),

// 2. 在 BottomNav 中添加图标
BottomNavigationBarItem(
  icon: Icon(Icons.shopping_cart),
  label: '购物车',
),

// 3. 在 _goToTab() 中添加跳转逻辑
case 2: context.go('/cart'); break;

添加新的独立页面

dart 复制代码
// 直接在 _buildIndependentRoutes() 中添加
GoRoute(
  path: '/settings',
  builder: (_, __) => const SettingsPage(),
),

💡 核心原理

ShellRoute 是关键

· 在 ShellRoute 内部:自动有底部导航

· 在 ShellRoute 外部:自动没有底部导航

状态管理

· tabIndexProvider:管理当前选中的标签页

· routerProvider:提供路由配置

跳转逻辑

· 点击底部导航:更新状态 + 路由跳转

· 页面间跳转:直接使用 context.go()

🎯 总结

这个方案的核心优势:

  1. 极简:最少的代码实现完整功能
  2. 清晰:路由分组一目了然
  3. 易用:添加页面只需1-3行代码
  4. 高效:利用框架特性,避免过度设计
相关推荐
等你等了那么久2 小时前
Flutter打包APK记录
flutter·dart
小a彤4 小时前
Flutter 与 Dart 语言的核心特性与应用
flutter
小a彤5 小时前
Flutter UI 美化与适配技巧详解
flutter·ui
500845 小时前
鸿蒙 Flutter 原子化服务进阶:轻量应用开发、跨设备流转与上架适配
java·flutter·华为·性能优化
kirk_wang6 小时前
Flutter插件跨平台适配技术分析之是否需要适配鸿蒙端-screenshot
flutter·华为·harmonyos
kirk_wang6 小时前
Flutter path_provider 在 OpenHarmony 平台上的实现与适配实践
flutter·移动开发·跨平台·arkts·鸿蒙
晚霞的不甘7 小时前
[鸿蒙2025领航者闯关] Flutter + OpenHarmony 模块化架构设计:大型应用的可维护性与协作之道
flutter·华为·harmonyos·鸿蒙·鸿蒙系统
测试人社区—66798 小时前
Jenkins持续测试集成
运维·人工智能·学习·flutter·ui·自动化·jenkins
帅气马战的账号18 小时前
开源鸿蒙+Flutter:跨端组件化与原生能力深度联动实战
flutter