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

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-

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:17:32