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

Flutter可复用BottomNavigationBar选中状态异常问题求助

问题描述

我希望实现可复用的BottomNavigationBar,此前了解到的同类方案多采用页面列表结合Scaffold的方式,不符合我的使用场景,想确认是否有可行的实现方式。当前我编写的代码中,通过Navigator跳转页面功能正常,但点击History按钮切换页面后,Home按钮仍保持红色选中状态,不清楚问题所在,恳请协助解决。

相关代码如下:

import 'package:conditional/HistoryScreen.dart';
import 'package:conditional/HomeScreen.dart';
import 'package:flutter/material.dart';

class NavBar extends StatefulWidget{
  NavBar({Key? key}):super(key: key);

  @override
  _NavBar createState() => _NavBar();
}


class _NavBar extends State<NavBar>{
  int currentIndex = 0;

  @override
  Widget build(BuildContext context){
    return BottomNavigationBar(
      currentIndex: currentIndex,
      onTap: (index){
        setState(() {
          currentIndex = index;
        });

        switch(index){
          case 0:
            Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen()));
            break;

          case 1:
            Navigator.push(context, MaterialPageRoute(builder: (context) => HistoryScreen()), );
            break;
        }
      },
      items: [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          activeIcon: Icon(Icons.home, color: currentIndex == 0 ? Colors.red : Colors.grey),
          label: "Home"),

        BottomNavigationBarItem(
          icon:Icon(Icons.history),
          activeIcon: Icon(Icons.history, color: currentIndex == 1 ? Colors.red : Colors.grey),
          label: "History" )
      ],
      selectedItemColor: Colors.red,
    );
  }
}
import 'package:conditional/NavBar.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget{
  HomeScreen({Key? key}):super(key: key);

  @override
  Widget build(BuildContext context){
    return Scaffold(
      body: Center(child: Text("This is Homescreen"),),
      bottomNavigationBar: NavBar(),
    );
  }
}
import 'package:conditional/NavBar.dart';
import 'package:flutter/material.dart';

class HistoryScreen extends StatefulWidget{
  HistoryScreen({Key? key}):super(key: key);

  @override
  _HistoryScreen createState()=> _HistoryScreen();
}

class _HistoryScreen extends State<HistoryScreen>{

  @override
  Widget build(BuildContext context){
    return Scaffold(
      body: Text("This is History Screen"),
      bottomNavigationBar: NavBar(),
    );
  }
}
问题原因

核心问题是每个页面都单独实例化了一个NavBar组件,每个NavBar都持有独立的currentIndex状态。点击History按钮跳转后,新打开的HistoryScreen里的NavBar初始currentIndex为0,默认选中Home按钮;而前一个页面的NavBar状态与新页面完全无关,导致视觉上出现选中状态错误的问题。

解决方案

针对你的需求(可复用NavBar+Navigator跳转),提供两种可行实现方式:

方式一:构造函数传递当前页面索引

修改NavBar为无状态组件,接收外部传入的当前索引和切换回调:

class NavBar extends StatelessWidget{
  final int currentIndex;
  final Function(int) onTabChange;

  const NavBar({Key? key, required this.currentIndex, required this.onTabChange}) : super(key: key);

  @override
  Widget build(BuildContext context){
    return BottomNavigationBar(
      currentIndex: currentIndex,
      onTap: onTabChange,
      items: const [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: "Home"),
        BottomNavigationBarItem(
          icon:Icon(Icons.history),
          label: "History" )
      ],
      selectedItemColor: Colors.red,
    );
  }
}

在各页面中指定对应索引:

// HomeScreen
class HomeScreen extends StatelessWidget{
  const HomeScreen({Key? key}):super(key: key);

  @override
  Widget build(BuildContext context){
    return Scaffold(
      body: const Center(child: Text("This is Homescreen"),),
      bottomNavigationBar: NavBar(
        currentIndex: 0,
        onTabChange: (index){
          if(index ==1){
            Navigator.push(context, MaterialPageRoute(builder: (context) => const HistoryScreen()));
          }
        },
      ),
    );
  }
}

// HistoryScreen
class HistoryScreen extends StatelessWidget{
  const HistoryScreen({Key? key}):super(key: key);

  @override
  Widget build(BuildContext context){
    return Scaffold(
      body: const Text("This is History Screen"),
      bottomNavigationBar: NavBar(
        currentIndex: 1,
        onTabChange: (index){
          if(index ==0){
            Navigator.push(context, MaterialPageRoute(builder: (context) => const HomeScreen()));
          }
        },
      ),
    );
  }
}

这种方式无需额外依赖,适合页面数量较少的场景。

方式二:全局状态管理共享选中索引

如果页面数量较多,推荐用状态管理库(如Provider、GetX)共享currentIndex状态,确保所有页面的NavBar同步选中状态。

以Provider为例:

  1. 创建状态类:
import 'package:flutter/material.dart';

class NavIndexProvider with ChangeNotifier {
  int _currentIndex = 0;

  int get currentIndex => _currentIndex;

  void setIndex(int index) {
    _currentIndex = index;
    notifyListeners();
  }
}
  1. 根组件注入Provider:
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => NavIndexProvider(),
      child: const MyApp(),
    ),
  );
}
  1. 修改NavBar组件:
class NavBar extends StatelessWidget{
  const NavBar({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context){
    final provider = Provider.of<NavIndexProvider>(context);
    return BottomNavigationBar(
      currentIndex: provider.currentIndex,
      onTap: (index){
        provider.setIndex(index);
        switch(index){
          case 0:
            Navigator.push(context, MaterialPageRoute(builder: (context) => const HomeScreen()));
            break;
          case 1:
            Navigator.push(context, MaterialPageRoute(builder: (context) => const HistoryScreen()));
            break;
        }
      },
      items: const [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          label: "Home"),
        BottomNavigationBarItem(
          icon:Icon(Icons.history),
          label: "History" )
      ],
      selectedItemColor: Colors.red,
    );
  }
}
  1. 页面组件直接使用NavBar即可,所有页面的选中状态会自动同步。
说明

两种方式都能避开页面列表+Scaffold的常规方案,满足可复用NavBar的需求,同时解决选中状态不同步的问题。第一种适合小型项目,第二种适合页面较多、需要全局状态同步的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:12:56