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
相关产品推荐
相关产品推荐

