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

Flutter中点击Done按钮后文本框内容消失的原因排查

问题原因分析及解决方案

核心问题原因

  1. StatelessWidget不适合持有可变状态
    你当前使用StatelessWidget,但组件内部的TextEditingController和value属于可变状态。StatelessWidget的build方法会在多种场景下触发重建(比如键盘收起、父组件状态变化),每次重建时这些状态无法被正确保留,容易被重置。

  2. 每次build强制重置控制器内容
    在build方法中直接执行controller.text = textForm ?? '';,这会导致每次组件重建时,控制器内容都会被强制覆盖为父组件传入的textForm值。当你点击Done按钮收起键盘时,组件触发重建,如果父组件没有将用户输入的内容同步更新到textForm参数中,控制器就会被重置为初始的textForm(大概率是空值),导致输入内容消失。

修复方案

最直接的解决方式是将组件改为StatefulWidget,把可变状态放到State类中管理,避免每次build时重置状态:

class CommentWidget extends StatefulWidget {
  final Function(String) onChanged;
  final String? textForm;
  final bool isHelpPage;

  CommentWidget({Key? key, required this.onChanged, required this.textForm, required this.isHelpPage})
      : super(key: key);

  @override
  State<CommentWidget> createState() => _CommentWidgetState();
}

class _CommentWidgetState extends State<CommentWidget> {
  final TextEditingController controller = TextEditingController();
  String value = '';

  @override
  void initState() {
    super.initState();
    // 仅在组件初始化时设置控制器初始值
    controller.text = widget.textForm ?? '';
    value = widget.textForm ?? '';
  }

  @override
  void didUpdateWidget(covariant CommentWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 仅当父组件传入的textForm发生变化时,才更新控制器内容
    if (oldWidget.textForm != widget.textForm) {
      controller.text = widget.textForm ?? '';
      value = widget.textForm ?? '';
    }
  }

  @override
  void dispose() {
    // 销毁控制器,避免内存泄漏
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        widget.isHelpPage
            ? const SizedBox()
            : const ResizedText(
                'Comments',
                textStyle: constants.Styles.smallTextStyleWhite,
              ),
        SizedBox(
          height: UiSize.getHeight(15, size),
        ),
        Container(
          height: UiSize.getHeight(widget.isHelpPage ? 290 : 150, size),
          width: UiSize.getWidth(360, size),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            border: Border.all(
              color: constants.Colors.purpleMain,
              width: 0.5,
            ),
          ),
          child: Padding(
            padding: EdgeInsets.only(
              top: UiSize.getHeight(16, size),
              left: UiSize.getWidth(18, size),
              right: UiSize.getWidth(18, size),
              bottom: UiSize.getHeight(16, size),
            ),
            child: TextField(
              maxLines: widget.isHelpPage ? 10 :4,
              maxLength: widget.isHelpPage ? 1500 : 450,
              controller: controller,
              style: constants.Styles.smallerBookTextStyleWhiteOpacity,
              textInputAction: TextInputAction.done,
              onChanged: (text) {
                widget.onChanged(text);
                value = text;
              },
              decoration: InputDecoration(
                border: InputBorder.none,
                helperStyle: constants.Styles.smallerBookTextStyleWhiteOpacity,
                hintStyle: constants.Styles.smallerBookTextStyleWhiteOpacity,
                hintText: 'Here you can describe the problem in more detail',
              ),
            ),
          ),
        ),
      ],
    );
  }
}

额外说明

如果坚持使用StatelessWidget,需要满足两个条件:

  • 父组件必须在onChanged回调中,将用户输入的内容同步更新到textForm参数,确保每次build时textForm是最新的输入值
  • 移除build方法中的controller.text = textForm ?? '';,改为在控制器初始化时设置初始值

但这种方式会增加父组件的状态管理复杂度,因此更推荐使用StatefulWidget的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 19:45:34