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, ), ), ])); }
问题原因分析
- 双层GestureDetector冲突:每个菜单项同时存在两层
GestureDetector(外层ListView.builder里的和内层drawerItems里的),点击时内层的页面跳转逻辑先执行,可能导致外层的setState触发不及时或被干扰。 - 多次调用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
相关产品推荐
相关产品推荐

