You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter go_router 5如何保持页面状态并预加载页面?

使用GoRouter 5实现底部导航栏的状态保持与预加载

GoRouter 5完全可以实现你要的底部导航状态保持和预加载效果,核心是结合IndexedStack与路由同步机制——IndexedStack负责缓存所有页面、保持状态并实现预加载,GoRouter则负责路由的管理与同步。

具体实现步骤

1. 配置路由结构

将所有底部导航标签页的路由指向同一个根页面(比如RootPage),这样无论切换哪个标签页路由,都由RootPage来管理页面的显示与缓存。

2. 实现根页面(底部导航容器)

在RootPage中:

  • 用IndexedStack包裹所有标签页的页面组件,初始化时所有页面会被一次性加载(实现预加载),切换时仅切换显示的索引,不会重建组件。
  • 维护当前选中的标签索引,监听GoRouter的路由变化,同步更新索引,确保底部导航高亮与当前路由匹配。
  • 底部导航的点击事件通过GoRouter的go方法跳转到对应路由,同时触发索引更新。

3. 同步路由与标签状态

通过监听GoRouter的路由变化,在路由切换时自动更新当前选中的标签索引;点击标签时,通过路由跳转来触发状态同步,保证路由栈的正确性。

完整代码示例

路由配置

final GoRouter router = GoRouter(
  initialLocation: '/home',
  routes: [
    // 默认重定向到首页
    GoRoute(
      path: '/',
      redirect: (context, state) => '/home',
    ),
    // 首页路由
    GoRoute(
      path: '/home',
      builder: (context, state) => const RootPage(),
    ),
    // 我的页面路由
    GoRoute(
      path: '/profile',
      builder: (context, state) => const RootPage(),
    ),
    // 可添加更多标签页路由
  ],
);

根页面实现

class RootPage extends StatefulWidget {
  const RootPage({super.key});

  @override
  State<RootPage> createState() => _RootPageState();
}

class _RootPageState extends State<RootPage> {
  // 预加载所有标签页页面
  final List<Widget> _pages = const [
    HomePage(), // 自定义首页组件,包含滚动列表等
    ProfilePage(), // 自定义我的页面组件
    // 添加更多标签页组件
  ];

  int _currentIndex = 0;

  // 路由路径与标签索引的映射
  final Map<String, int> _routeIndexMap = {
    '/home': 0,
    '/profile': 1,
    // 对应更多路由与索引
  };

  @override
  void initState() {
    super.initState();
    // 初始化时根据当前路由设置选中索引
    _syncIndexWithRoute(GoRouter.of(context).location);
    // 监听路由变化,同步索引
    GoRouter.of(context).addListener(_onRouteChanged);
  }

  @override
  void dispose() {
    // 移除路由监听
    GoRouter.of(context).removeListener(_onRouteChanged);
    super.dispose();
  }

  void _onRouteChanged() {
    final currentRoute = GoRouter.of(context).location;
    _syncIndexWithRoute(currentRoute);
  }

  void _syncIndexWithRoute(String route) {
    setState(() {
      _currentIndex = _routeIndexMap[route] ?? 0;
    });
  }

  void _onTabTap(int index) {
    // 根据索引找到对应路由并跳转
    final targetRoute = _routeIndexMap.entries
        .firstWhere((entry) => entry.value == index)
        .key;
    GoRouter.of(context).go(targetRoute);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // IndexedStack缓存所有页面,保持状态
      body: IndexedStack(
        index: _currentIndex,
        children: _pages,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: _onTabTap,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home_outlined),
            activeIcon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person_outline),
            activeIcon: Icon(Icons.person),
            label: '我的',
          ),
          // 添加更多导航项
        ],
      ),
    );
  }
}

关键说明

  • 预加载效果:IndexedStack在初始化时会创建所有子组件,启动时所有标签页页面都会被预加载完成,切换时无需重新加载,响应迅速。
  • 状态保持:IndexedStack会保留每个子组件的状态,包括滚动位置、输入框内容等,切换标签页后返回时状态完全恢复。
  • 路由同步:通过监听路由变化,确保底部导航的选中状态与当前路由一致,同时支持通过浏览器地址栏、深层链接直接跳转到对应标签页,符合GoRouter的路由管理逻辑。

内容的提问来源于stack exchange,提问作者Destrankir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:30:51