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

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<String, List<String>> displayRules = {
      'A': ['AreaGeo'],
      'B': ['AreaGeo', 'RadiusGeo', 'DiameterGeo', 'CircumferenceGeo'],
      'C': ['RadiusGeo'],
      'D': ['AreaGeo', 'RadiusGeo', 'CircumferenceGeo'],
    };
    
    之后通过遍历Map匹配规则渲染输入框,代码更简洁易维护。
  • 若需保留输入框状态(比如输入内容不丢失),可使用Visibility组件替代if,但if方式更高效——不渲染的组件不会加入组件树。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 05:35:39