Flutter中点击Done按钮后文本框内容消失的原因排查
问题原因分析及解决方案
核心问题原因
StatelessWidget不适合持有可变状态
你当前使用StatelessWidget,但组件内部的TextEditingController和value属于可变状态。StatelessWidget的build方法会在多种场景下触发重建(比如键盘收起、父组件状态变化),每次重建时这些状态无法被正确保留,容易被重置。每次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
相关产品推荐
相关产品推荐

