Flutter中从BottomNavigationBar页面调用pushReplacement并选中首页Tab的方法
问题根因
你出现双重底部导航栏的核心原因是:你调用了Navigator.of(context).pushReplacement加载新的App实例,相当于在当前搜索页内部的独立导航栈中又嵌套了一层完整的带底部导航的App结构,两个导航栏就叠加显示了。
你当前的架构里每个Tab都自带独立的Navigator,所有Tab共享同一个外层App的底部导航,你不需要跳转新页面,只需要切换外层App的当前选中Tab索引即可。
解决方案
步骤1:修改AppState,暴露状态调用入口和Tab切换方法
- 把私有方法
_selectTab改为公开方法selectTab,同时调整内部所有调用处的命名 - 新增
of方法方便子组件获取AppState实例
修改后的AppState核心代码:
class AppState extends State<App> { static int currentTab = 0; final List<TabItem> tabs = [ TabItem( tabName: "Home", icon: Icons.home_outlined, page: HomePage(), ), TabItem( tabName: "Search", icon: Icons.search, page: SearchPage(), ), ]; // 新增of方法,供子组件获取AppState实例 static AppState of(BuildContext context) { return context.findAncestorStateOfType<AppState>()!; } AppState() { tabs.asMap().forEach((index, details) { details.setIndex(index); }); } // 下划线去掉,改为公开方法 void selectTab(int index) { if (index == currentTab) { tabs[index].key.currentState!.popUntil((route) => route.isFirst); } else { setState(() => currentTab = index); } } @override Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { final isFirstRouteInCurrentTab = !await tabs[currentTab].key.currentState!.maybePop(); if (isFirstRouteInCurrentTab) { if (currentTab != 0) { // 调用改为公开方法 selectTab(0); return false; } } return isFirstRouteInCurrentTab; }, child: Scaffold( body: IndexedStack( index: currentTab, children: tabs.map((e) => e.page).toList(), ), bottomNavigationBar: BottomNavigation( // 传公开方法 onSelectTab: selectTab, tabs: tabs, ), ), ); } }
步骤2:修改SearchPage的按钮点击逻辑
删除原有的路由跳转代码,直接调用AppState的selectTab方法切换到首页Tab(索引为0):
class _SearchPageState extends State<SearchPage> { @override Widget build(BuildContext context) { return Scaffold( body: Container( child: Center( child: TextButton( onPressed: () { // 直接调用外层App的切换Tab方法 AppState.of(context).selectTab(0); }, child: Text('Switch'), ), ), ), ); } }
效果说明
修改后点击搜索页的按钮,会直接切换到底部导航的首页选中状态,首页会重置到导航栈最顶层,和应用刚启动的展示效果完全一致,不会再出现双重导航栏的问题。
内容的提问来源于stack exchange,提问作者Mohammed Nabil
相关产品推荐
相关产品推荐

