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

Flutter自定义DropdownButton选中后无法显示选中值问题求助

我正在尝试为DropdownButton创建自定义Widget,组件运行基本正常,触发onChanged()函数时控制台可打印出变更后的值,但执行onChanged()后下拉框无法显示选中的文本。

我的组件代码如下:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class InputScreen2 extends StatefulWidget {
  final List<double> sizes;
  const InputScreen2({Key? key, required widget.sizes}) : super(key: key);

  @override
  State<InputScreen2> createState() => _InputScreen2State();
}

class _InputScreen2State extends State<InputScreen2> {
  Future? future;
  double screenwd = 0, screenht = 0;
  List<String> listsex = ['Male', 'Female'];
  String? sex;

  @override
  void initState() {
    future = _future();
    super.initState();
  }

  Future<int> _future() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    screenwd = widget.sizes[0];
    screenht = widget.sizes[1];

    return 0;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.orange,
        body: FutureBuilder(
            future: future,
            builder: (context, snapshot) {
              if (snapshot.hasError) {
                return Center(
                    child: Text(
                  'Data Error...Please try again',
                  style: Theme.of(context).textTheme.titleSmall,
                ));
              } else if (snapshot.connectionState == ConnectionState.waiting) {
                return Text(
                  'Waiting',
                  style: Theme.of(context).textTheme.titleSmall,
                );
              } else if (!snapshot.hasData) {
                return Text(
                  'No Data',
                  style: Theme.of(context).textTheme.titleSmall,
                );
              } else if (snapshot.hasData) {
                return SafeArea(
                  child: Center(
                    child: Container(
                      padding: const EdgeInsets.all(20.0),
                      decoration: BoxDecoration(
                          border: Border.all(width: 2.0), color: Colors.blue),
                      width: screenwd * .8,
                      height: screenht * .75,
                      child: SingleChildScrollView(
                        child: Column(
                          children: [
                            Row(
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                const Text(
                                  'Personal Details',
                                ),
                                const SizedBox(
                                  width: 23,
                                ),
                                dropDownMenu('Sex', sex, listsex),
                              ],
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                );
              }
              return const Text('No DATA');
            }));
  }

  Widget dropDownMenu(String title, String? inputTxt, List<String> stringList) {
    return Container(
      margin: const EdgeInsets.only(top: 10.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
          ),
          Container(
            width: 80,
            height: 35,
            decoration: BoxDecoration(
                border: Border.all(color: Colors.white, width: 1.0),
                borderRadius: const BorderRadius.all(Radius.circular(5.0))),
            child: DropdownButton<String>(
                value: inputTxt,
                dropdownColor: Colors.amber,
                items: stringList.map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                      value: value,
                      child: Text(
                        value,
                        style: const TextStyle(color: Colors.white),
                      ));
                }).toList(),
                onChanged: (String? value) {
                  setState(() {
                    inputTxt = value!;
                  });
                }),
          ),
        ],
      ),
    );
  }
}

问题原因

问题核心在于自定义的dropDownMenu函数中:

  • inputTxt是函数的局部参数,你在onChanged里调用setState修改的只是这个局部变量,并没有更新State类中定义的sex变量。
  • Flutter的UI渲染依赖State的状态值,由于sex没有变化,DropdownButton的value始终保持初始值,导致选中后文本不更新。

解决方法

方法一:直接更新State中的变量

修改dropDownMenu函数的onChanged回调,直接操作State中的sex变量:

// 修改dropDownMenu内的onChanged部分
onChanged: (String? value) {
  setState(() {
    sex = value!; // 直接更新State中的sex变量
  });
}

这样当选中选项时,sex变量被更新,setState触发UI重建,DropdownButton的value会同步为新选中的值,就能正确显示选中文本。

方法二:通过回调实现通用组件(推荐)

如果希望dropDownMenu作为通用组件,不直接依赖父组件的State变量,可以添加回调参数:

  1. 修改dropDownMenu函数定义,增加回调参数:
Widget dropDownMenu(
  String title,
  String? inputTxt,
  List<String> stringList,
  Function(String?) onValueChanged, // 新增回调参数
) {
  return Container(
    // ... 其他代码不变
    child: DropdownButton<String>(
      value: inputTxt,
      // ... 其他代码不变
      onChanged: onValueChanged, // 使用传入的回调
    ),
  );
}
  1. 在调用dropDownMenu时传入回调:
dropDownMenu('Sex', sex, listsex, (value) {
  setState(() {
    sex = value!;
  });
})

这种写法让自定义组件更灵活,可复用性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:54:54