Flutter导航问题:context.push()后返回按钮致底部导航栏索引异常
Flutter底部导航栏返回后索引重置问题
问题描述
开发带底部导航栏的Flutter应用,点击标签页通过context.push('/createPost')跳转到发帖页面。从发帖页点击系统返回按钮后,无论跳转前处于哪个标签页,底部导航栏的选中索引都会被重置为0,但页面显示的是跳转前的正确页面。
相关代码
ScaffoldWithNavBar组件
class ScaffoldWithNavBar extends StatefulWidget { final String location; const ScaffoldWithNavBar( {super.key, required this.child, required this.location}); final Widget child; @override State<ScaffoldWithNavBar> createState() => _ScaffoldWithNavBarState(); } class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> { int _currentIndex = 0; int _previousIndex = 0; static const List<MyCustomBottomNavBarItem> tabs = [ MyCustomBottomNavBarItem( initialLocation: '/home', label: 'Home', icon: Icon(Clarity.home_line), activeIcon: Icon(Clarity.home_line), ), MyCustomBottomNavBarItem( initialLocation: '/map', label: 'Map', icon: Icon(Clarity.map_line), activeIcon: Icon(Clarity.map_line), ), MyCustomBottomNavBarItem( initialLocation: '/createPost', label: 'Create Post', icon: Icon(Clarity.plus_circle_line), activeIcon: Icon(Clarity.plus_circle_line), ), MyCustomBottomNavBarItem( initialLocation: '/discover', label: 'Discover', icon: Icon(Clarity.search_line), activeIcon: Icon(Clarity.search_line), ), MyCustomBottomNavBarItem( initialLocation: '/profile', label: 'Profile', icon: Icon(Clarity.user_line), activeIcon: Icon(Clarity.user_line), ) ]; @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: widget.child, ), bottomNavigationBar: BottomNavigationBar( selectedItemColor: BlndColors.red, unselectedItemColor: BlndColors.brown, showSelectedLabels: false, showUnselectedLabels: false, iconSize: 30.0, type: BottomNavigationBarType.fixed, onTap: (int index) { _goOtherTab(context, index); }, currentIndex: widget.location == '/home' ? 0 : widget.location == '/map' ? 1 : widget.location == '/discover' ? 3 : widget.location == '/profile' ? 4 : 2, items: tabs, ), ); } }
_goOtherTab方法
void _goOtherTab(BuildContext context, int index) { if (index == _currentIndex) return; GoRouter router = GoRouter.of(context); String location = tabs[index].initialLocation; if (index != 2) { _previousIndex = _currentIndex; print('previous index: $_previousIndex'); } setState(() { _currentIndex = index; }); if (index == 2) { context.push('/createPost').then((value) { _currentIndex = _previousIndex; print('current index after push: $_currentIndex'); }); } else { print('current index: $_currentIndex'); router.go(location); } } }
路由配置
final _rootNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorKey = GlobalKey<NavigatorState>(); final GoRouter router = GoRouter( initialLocation: '/', navigatorKey: _rootNavigatorKey, routes: [ ShellRoute( navigatorKey: _shellNavigatorKey, pageBuilder: (context, state, child) { return NoTransitionPage( child: ScaffoldWithNavBar( location: state.matchedLocation, child: child, ), ); }, routes: [ GoRoute( name: 'home', path: '/home', parentNavigatorKey: _shellNavigatorKey, builder: (context, state) => const HomePage(), ), GoRoute( name: 'map', path: '/map', parentNavigatorKey: _shellNavigatorKey, builder: (context, state) => const MapPage(), ), GoRoute( name: 'discover', path: '/discover', parentNavigatorKey: _shellNavigatorKey, builder: (context, state) => const DiscoverPage(), ), GoRoute( name: 'profile', path: '/profile', parentNavigatorKey: _shellNavigatorKey, builder: (context, state) => const ProfilePage(), ), ], ), GoRoute( name: 'builder', path: '/', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const BuilderWidget(), ), GoRoute( name: 'signIn', path: '/signIn', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const SignInPage(), ), GoRoute( name: 'signUp', path: '/signUp', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const SignUpPage(), ), GoRoute( name: 'createPost', path: '/createPost', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const CreatePostPage(), ), ], );
已尝试方案
- 跳转前存储原索引,返回后恢复索引,但无效
- 查阅go_router官方文档,未找到对应问题的解决细节
解决方案
问题核心在于底部导航栏的选中索引直接依赖widget.location判断,而非状态变量_currentIndex,且返回后更新_currentIndex未触发UI刷新。修改步骤如下:
1. 同步状态与路由路径
在_ScaffoldWithNavBarState中添加方法,确保_currentIndex始终与当前路由路径同步:
@override void initState() { super.initState(); _syncCurrentIndexWithLocation(); } @override void didUpdateWidget(covariant ScaffoldWithNavBar oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.location != widget.location) { _syncCurrentIndexWithLocation(); } } void _syncCurrentIndexWithLocation() { setState(() { // 根据当前路由路径匹配对应的标签索引 _currentIndex = tabs.indexWhere((tab) => tab.initialLocation == widget.location); // 处理匹配失败的情况(默认选中首页) if (_currentIndex == -1) { _currentIndex = 0; } }); }
2. 底部导航栏使用状态变量控制选中索引
修改BottomNavigationBar的currentIndex属性,从基于widget.location判断改为直接使用_currentIndex:
currentIndex: _currentIndex,
3. 返回后触发UI刷新
在_goOtherTab方法中,从发帖页返回后更新_currentIndex时调用setState,确保底部导航栏UI更新:
if (index == 2) { context.push('/createPost').then((value) { setState(() { _currentIndex = _previousIndex; }); print('current index after push: $_currentIndex'); }); }
完成以上修改后,从发帖页返回时,底部导航栏的选中索引会正确恢复到跳转前的标签页,不会再出现重置为0的问题。
内容的提问来源于stack exchange,提问作者Lyne-
相关产品推荐
相关产品推荐

