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

Flutter:页面切换时底部导航图标颜色切换问题(setState无效)

解决底部导航图标选中态变色问题

你的问题核心在于每个页面都是通过Navigator.push跳转,导致每个页面都有独立的底部导航栏实例,状态无法共享,所以单独用setState只会更新当前页面的导航栏,切换后新页面的导航栏还是初始状态。下面给你两种可行的解决方案:

方案一:标准底部导航+页面切换(推荐)

这种方式是Flutter底部导航的常规实现,用父组件管理选中索引,通过IndexedStack切换页面,导航栏状态统一维护:

class _CustomBottomNavigationState extends State<CustomBottomNavigation> {
  // 维护当前选中的页面索引
  int _selectedIndex = 0;

  // 页面列表,对应导航项
  final List<Widget> _pages = [
    MyScreen(),
    My2Screen(),
    My3Screen(),
    My4Screen(),
  ];

  // 更新选中索引
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    return Scaffold(
      // 显示当前选中的页面,保留页面状态
      body: IndexedStack(
        index: _selectedIndex,
        children: _pages,
      ),
      bottomNavigationBar: Container(
        width: size.width,
        height: 80,
        child: Stack(
          children: [
            CustomPaint(
              size: Size(size.width, 80),
              painter: BNBCustomPainter(),
            ),
            Center(
              heightFactor: 0.6,
              child: FloatingActionButton(
                onPressed: () {
                  widget._addingThings(context);
                },
                backgroundColor: Colors.black,
                child: Icon(Icons.add),
                elevation: 0.1,
              ),
            ),
            Container(
              width: size.width,
              height: 80,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  IconButton(
                    // 根据选中状态设置颜色
                    icon: Icon(Icons.home, color: _selectedIndex == 0 ? Colors.blue : Colors.grey),
                    onPressed: () => _onItemTapped(0),
                  ),
                  IconButton(
                    icon: Icon(Icons.notifications, color: _selectedIndex == 1 ? Colors.blue : Colors.grey),
                    onPressed: () => _onItemTapped(1),
                  ),
                  Container(width: size.width * 0.2),
                  IconButton(
                    icon: Icon(Icons.add, color: _selectedIndex == 2 ? Colors.blue : Colors.grey),
                    onPressed: () {
                      _pickImageFromCamera();
                      _onItemTapped(2);
                    },
                  ),
                  IconButton(
                    icon: Icon(Icons.abc, color: _selectedIndex == 3 ? Colors.blue : Colors.grey),
                    onPressed: () => _onItemTapped(3),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

方案二:保留Navigator.push,监听路由更新状态

如果你坚持用Navigator.push跳转页面,需要在导航栏组件中监听当前路由,根据路由名称匹配选中状态:

class _CustomBottomNavigationState extends State<CustomBottomNavigation> {
  int _selectedIndex = 0;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // 每次依赖变化时更新选中索引(比如路由切换后)
    _updateSelectedIndex();
  }

  void _updateSelectedIndex() {
    final routeName = ModalRoute.of(context)?.settings.name;
    setState(() {
      switch(routeName) {
        case '/myScreen':
          _selectedIndex = 0;
          break;
        case '/my2Screen':
          _selectedIndex = 1;
          break;
        case '/my3Screen':
          _selectedIndex = 2;
          break;
        case '/my4Screen':
          _selectedIndex = 3;
          break;
        default:
          _selectedIndex = 0;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    return Container(
      width: size.width,
      height: 80,
      child: Stack(
        children: [
          CustomPaint(
            size: Size(size.width, 80),
            painter: BNBCustomPainter(),
          ),
          Center(
            heightFactor: 0.6,
            child: FloatingActionButton(
              onPressed: () {
                widget._addingThings(context);
              },
              backgroundColor: Colors.black,
              child: Icon(Icons.add),
              elevation:0.1,
            ),
          ),
          Container(
            width: size.width,
            height: 80,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                IconButton(
                  icon: Icon(Icons.home, color: _selectedIndex == 0 ? Colors.blue : Colors.grey),
                  onPressed: () {
                    Navigator.pushNamed(context, '/myScreen');
                  }
                ),
                IconButton(
                  icon: Icon(Icons.notifications, color: _selectedIndex == 1 ? Colors.blue : Colors.grey),
                  onPressed: () {
                    Navigator.pushNamed(context, '/my2Screen');
                  }
                ),
                Container(width: size.width * 0.2),
                IconButton(
                  icon: Icon(Icons.add, color: _selectedIndex == 2 ? Colors.blue : Colors.grey),
                  onPressed: () {
                    _pickImageFromCamera();
                    Navigator.pushNamed(context, '/my3Screen');
                  }
                ),
                IconButton(
                  icon: Icon(Icons.abc, color: _selectedIndex == 3 ? Colors.blue : Colors.grey),
                  onPressed: () {
                    Navigator.pushNamed(context, '/my4Screen');
                  }
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

注意:方案二需要你在路由表中给每个页面配置名称,示例如下:

MaterialApp(
  initialRoute: '/myScreen',
  routes: {
    '/myScreen': (context) => MyScreen(),
    '/my2Screen': (context) => My2Screen(),
    '/my3Screen': (context) => My3Screen(),
    '/my4Screen': (context) => My4Screen(),
  },
)

关键说明

  • 方案一的优势是状态管理更简单,页面切换无堆叠,性能更好,是官方推荐的底部导航实现方式
  • 方案二更适合需要保留页面栈的场景,但需要额外维护路由名称和索引的映射关系

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 07:57:50