Flutter中在Drawer Header添加Dropdown Button遇setState错误求助
问题原因
你的MainDrawer是StatelessWidget,这类组件没有内部状态管理能力,无法调用setState方法——而DropdownButtonFormField需要通过setState更新选中状态,触发组件重新渲染,这就是错误的根源。
解决方案
提供两种可行的修复方式,根据你的需求选择:
方案一:将MainDrawer改为StatefulWidget
把整个抽屉组件改为有状态组件,统一管理Dropdown的状态:
import 'package:flutter/material.dart'; import 'package:test/Screens/change_password_screen.dart'; import 'package:test/Screens/login_screen.dart'; class MainDrawer extends StatefulWidget { const MainDrawer({super.key}); @override State<MainDrawer> createState() => _MainDrawerState(); } class _MainDrawerState extends State<MainDrawer> { // 把状态变量移到State类中 List<String> itemsList = ['1', '2']; String? selectedItem = '1'; @override Widget build(BuildContext context) { return Drawer( width: 250, child: ListView( children: <Widget>[ DrawerHeader( decoration: BoxDecoration( border: Border.all(color: Colors.white), image: const DecorationImage( image: AssetImage("assets/images/logo.png"), )), // 用Column同时容纳文本和Dropdown组件 child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ const Text( "Example@hotmail.com", style: TextStyle( color: Colors.black, fontSize: 14.0, fontWeight: FontWeight.normal, ), ), const SizedBox(height: 10), Container( padding: const EdgeInsets.symmetric(horizontal: 25.0, vertical: 0.0), child: SizedBox( height: 40, child: DropdownButtonFormField<String>( decoration: const InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide( width: 1, color: Colors.grey, ))), value: selectedItem, items: itemsList .map((item) => DropdownMenuItem( value: item, child: Text(item), )) .toList(), onChanged: (item) => setState(() => selectedItem = item)), ), ), ], ), ), const Divider( color: Colors.black, height: 10, thickness: 1, ), // 以下ListTile和Divider代码保持不变 ListTile( leading: Image.asset("assets/images/exampla.png"), title: const Text( 'exampla', style: TextStyle( color: Colors.black, fontSize: 14.0, fontWeight: FontWeight.normal, ), ), onTap: null, ), const Divider(color: Colors.black, height: 10, thickness: 1), ListTile( leading: Image.asset("assets/images/examplb.png"), title: const Text( 'examplb', style: TextStyle( color: Colors.black, fontSize: 14.0, fontWeight: FontWeight.normal, ), ), onTap: null, ), const Divider(color: Colors.black, height: 10, thickness: 1), ListTile( leading: Image.asset("assets/images/examplc.png"), title: const Text( 'examplc', style: TextStyle( color: Colors.black, fontSize: 14.0, fontWeight: FontWeight.normal, ), ), onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const ExamplzScreen()), ); }, ), const Divider(color: Colors.black, height: 10, thickness: 1), ListTile( leading: Image.asset("assets/images/logout.png"), title: const Text( 'Log out', style: TextStyle( color: Colors.black, fontSize: 14.0, fontWeight: FontWeight.normal, ), ), onTap: () { Navigator.push( context, MaterialPageRoute(builder: (context) => const LoginScreen()), ); }, ), const Divider(color: Colors.black, height: 10, thickness: 1), ], ), ); } }
方案二:用StatefulBuilder局部管理Dropdown状态
如果不想修改整个组件的类型,可通过StatefulBuilder为Dropdown创建局部状态:
修改DrawerHeader部分的代码即可:
DrawerHeader( decoration: BoxDecoration( border: Border.all(color: Colors.white), image: const DecorationImage( image: AssetImage("assets/images/logo.png"), )), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ const Text( "Example@hotmail.com", style: TextStyle( color: Colors.black, fontSize: 14.0, fontWeight: FontWeight.normal, ), ), const SizedBox(height: 10), // 用StatefulBuilder包裹Dropdown,提供局部setState StatefulBuilder( builder: (context, setState) { List<String> itemsList = ['1', '2']; String? selectedItem = '1'; return Container( padding: const EdgeInsets.symmetric(horizontal: 25.0, vertical: 0.0), child: SizedBox( height: 40, child: DropdownButtonFormField<String>( decoration: const InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide( width: 1, color: Colors.grey, ))), value: selectedItem, items: itemsList .map((item) => DropdownMenuItem( value: item, child: Text(item), )) .toList(), onChanged: (item) => setState(() => selectedItem = item)), ), ); }, ), ], ), ),
内容的提问来源于stack exchange,提问作者sarah
相关产品推荐
相关产品推荐

