Flutter中DropdownButtonFormField切换显示对应TextFormField实现方案
Flutter 动态根据下拉选项显示对应输入框实现方案
核心实现思路
通过setState更新下拉选中值,利用条件渲染控制每个TextFormField的显示/隐藏——本质是根据selectedValue的取值,决定是否将对应输入框加入组件树。
具体代码修改
1. 初始化下拉选项与选中值
先确保下拉选项和默认选中值已正确定义:
// 示例下拉选项,可根据实际需求修改 List<String> dropdownOptions = ['A', 'B', 'C', 'D']; String? selectedValue = 'A'; // 设置默认选中项
2. 下拉回调逻辑(你的原有代码已正确,补充说明)
onChanged回调只需通过setState更新selectedValue,触发组件重建即可更新输入框的显示状态:
onChanged: (String? newValue) { setState(() { selectedValue = newValue!; }); },
3. 动态控制输入框显示
将每个inputForm用条件判断包裹,根据selectedValue决定是否渲染。示例规则:
- 选中A:仅显示AreaGeo输入框
- 选中B:显示全部4个输入框
- 选中C:仅显示RadiusGeo输入框
- 选中D:显示AreaGeo、RadiusGeo和CircumferenceGeo输入框
修改后的完整代码片段:
return SingleChildScrollView( child: Container( child: Column( children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 15), child: Column( children: [ DropdownButtonFormField( decoration: const InputDecoration(labelText: 'Calculate'), value: selectedValue, onChanged: (String? newValue) { setState(() { selectedValue = newValue!; }); }, items: dropdownOptions .map((option) => DropdownMenuItem( value: option, child: Text(option), )) .toList(), ), const SizedBox(height: 20), // 选中A/B/D时显示AreaGeo输入框 if (selectedValue == 'A' || selectedValue == 'B' || selectedValue == 'D') inputForm( title: locale.translate('AreaGeo')!, controller: _controller1, suffix: locale.translate('AreaSuffix')!, ), // 选中B/C/D时显示RadiusGeo输入框 if (selectedValue == 'B' || selectedValue == 'C' || selectedValue == 'D') inputForm( title: locale.translate('RadiusGeo')!, controller: _controller2, suffix: locale.translate('RadiusSuffix')!, ), // 选中B时显示DiameterGeo输入框 if (selectedValue == 'B') inputForm( title: locale.translate('DiameterGeo')!, controller: _controller3, suffix: locale.translate('LengthSuffix')!, ), // 选中B/D时显示CircumferenceGeo输入框 if (selectedValue == 'B' || selectedValue == 'D') inputForm( title: locale.translate('CircumferenceGeo')!, controller: _controller4, suffix: locale.translate('LengthSuffix')!, ), // 原有计算按钮逻辑保持不变 GestureDetector( onTap: () { loanCalculation(); Future.delayed(Duration.zero); showModalBottomSheet( isScrollControlled: true, isDismissible: false, shape: const RoundedRectangleBorder( borderRadius: BorderRadiusDirectional.only( topEnd: Radius.circular(18), topStart: Radius.circular(18), ), ), context: context, builder: (context) => SingleChildScrollView( child: Wrap( children: [ Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), Center( child: Container( width: 80, height: 5, decoration: BoxDecoration( color: Colors.grey[700], borderRadius: BorderRadius.circular(15), ), ), ), const SizedBox(height: 15), Padding( padding: const EdgeInsets.fromLTRB(20, 10, 0, 10), child: Column( children: [ result( title: locale.translate('AreaGeo')!, amount: area), result( title: locale.translate('RadiusGeo')!, amount: radiusC), result( title: locale.translate('DiameterGeo')!, amount: diameter), result( title: locale.translate('CircumferenceGeo')!, amount: circumference), ], ), ), const SizedBox(height: 15), GestureDetector( onTap: () { Navigator.of(context).pop(); }, child: Padding( padding: const EdgeInsets.fromLTRB(30, 10, 30, 30), child: Container( height: 60, width: double.infinity, decoration: BoxDecoration( color: UnitConverterApp.isDarkMode ? AppColors.accentDarkColor : AppColors.accentLightColor, borderRadius: BorderRadius.circular(10), ), child: Center( child: Text( locale.translate('ReCalculate')!, style: style, )), ), ), ), ], ), ), ], ), ), ); }, child: Container( height: 60, width: double.infinity, decoration: BoxDecoration( color: UnitConverterApp.isDarkMode ? AppColors.accentDarkColor : AppColors.accentLightColor, borderRadius: BorderRadius.circular(10), ), child: Center( child: Text( locale.translate('Calculate')!, style: style, )), ), ), ], ), ), ], ), ), );
额外优化建议
- 如果显示规则复杂,可将选项与对应显示的输入框列表抽成Map,避免重复写条件:
之后通过遍历Map匹配规则渲染输入框,代码更简洁易维护。Map<String, List<String>> displayRules = { 'A': ['AreaGeo'], 'B': ['AreaGeo', 'RadiusGeo', 'DiameterGeo', 'CircumferenceGeo'], 'C': ['RadiusGeo'], 'D': ['AreaGeo', 'RadiusGeo', 'CircumferenceGeo'], }; - 若需保留输入框状态(比如输入内容不丢失),可使用
Visibility组件替代if,但if方式更高效——不渲染的组件不会加入组件树。
内容的提问来源于stack exchange,提问作者Abu Bakar
相关产品推荐
相关产品推荐

