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

Flutter抽屉选中菜单项颜色修改问题求助

Flutter Drawer选中菜单项颜色不生效问题排查

我在用Flutter开发应用时,遇到Drawer组件无法修改选中菜单项颜色的问题,逻辑看似正常但始终不生效,以下是完整代码,恳请帮忙排查问题所在:

抽屉组件代码

class _DrawerClassState extends State<DrawerClass> {
  List<String> menuStrings = [
    'HOME',
    'NOTIFICATIONS',
    'PARTNERS',
    'LOCATIONS',
    'FEEDBACK',
    'CONTACT US',
    'AWARDS'
  ];

  List menuScreens = [
    HomeScreen(),
    Notifications(),
    Partners(),
    Locations(),
    FeedbackScreen(),
    const ContactUs(),
    Awards()
  ];

  List<bool> isHighlighted = [false, false, false, false, true, false, false];

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        canvasColor: Colors.black,
      ),
      child: Drawer(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            drawerTop("HI USER"),
            ListView.builder(
              shrinkWrap: true,
              itemCount: menuScreens.length,
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () {
                    for (int i = 0; i < isHighlighted.length; i++) {
                      setState(() {
                        if (index == i) {
                          isHighlighted[index] = true;
                        } else {
                          isHighlighted[i] = false;
                        }
                      });
                    }
                  },
                  child: drawerItems(
                    context,
                    menuStrings[index],
                    menuScreens[index],
                    isHighlighted[index] ? Colors.amber : Colors.white,
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

抽屉项构建方法

drawerItems(BuildContext context, String title, path, Color color) {
    return Padding(
        padding: EdgeInsets.only(
            top: 0.0, left: MediaQuery.of(context).size.width * 0.1),
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          GestureDetector(
            onTap: () {
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: ((context) => path)));
            },
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 8.0),
              child: Text(
                title,
                style: TextStyle(
                    color: color,
                    fontFamily: "Raleway Reg",
                    fontSize: 23,
                    letterSpacing: 2),
              ),
            ),
          ),
          SizedBox(
            width: MediaQuery.of(context).size.width * 0.5,
            child: const Divider(
              thickness: 1,
              color: Colors.white,
              height: 3,
            ),
          ),
        ]));
  }

问题原因分析

  1. 双层GestureDetector冲突:每个菜单项同时存在两层GestureDetector(外层ListView.builder里的和内层drawerItems里的),点击时内层的页面跳转逻辑先执行,可能导致外层的setState触发不及时或被干扰。
  2. 多次调用setState:在循环中逐个修改isHighlighted元素并每次调用setState,会触发多次不必要的重绘,且状态更新逻辑冗余,容易导致状态不同步。

解决方案

1. 合并点击逻辑,移除内层GestureDetector

把页面跳转逻辑移到外层的onTap中,避免两层点击事件冲突,确保状态更新和页面跳转顺序正确。

2. 优化状态更新方式

用单个变量记录选中索引(替代布尔列表),简化状态管理,同时只调用一次setState完成状态更新。

修改后的完整代码

class _DrawerClassState extends State<DrawerClass> {
  List<String> menuStrings = [
    'HOME',
    'NOTIFICATIONS',
    'PARTNERS',
    'LOCATIONS',
    'FEEDBACK',
    'CONTACT US',
    'AWARDS'
  ];

  List menuScreens = [
    HomeScreen(),
    Notifications(),
    Partners(),
    Locations(),
    FeedbackScreen(),
    const ContactUs(),
    Awards()
  ];

  // 用单个变量记录选中的索引,初始选中FEEDBACK(索引4)
  int selectedIndex = 4;

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        canvasColor: Colors.black,
      ),
      child: Drawer(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            drawerTop("HI USER"),
            ListView.builder(
              shrinkWrap: true,
              itemCount: menuScreens.length,
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () {
                    // 先更新选中状态,再执行页面跳转
                    setState(() {
                      selectedIndex = index;
                    });
                    Navigator.of(context).push(MaterialPageRoute(builder: ((context) => menuScreens[index])));
                  },
                  child: drawerItems(
                    context,
                    menuStrings[index],
                    selectedIndex == index ? Colors.amber : Colors.white,
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }

  // 移除内层GestureDetector,简化drawerItems方法
  drawerItems(BuildContext context, String title, Color color) {
    return Padding(
        padding: EdgeInsets.only(
            top: 0.0, left: MediaQuery.of(context).size.width * 0.1),
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8.0),
            child: Text(
              title,
              style: TextStyle(
                  color: color,
                  fontFamily: "Raleway Reg",
                  fontSize: 23,
                  letterSpacing: 2),
            ),
          ),
          SizedBox(
            width: MediaQuery.of(context).size.width * 0.5,
            child: const Divider(
              thickness: 1,
              color: Colors.white,
              height: 3,
            ),
          ),
        ]));
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:24:20