Flutter自定义TextField聚焦时触发'!_dirty'断言错误求助
解决TextField聚焦时触发'!_dirty'断言错误的问题
问题分析
你遇到的'!_dirty': is not true断言错误,核心原因是在WidgetStatesController的监听回调中直接调用setState,此时TextField正处于框架的更新流程中(组件标记为dirty),强行触发状态更新会打乱框架的更新顺序,导致断言失败。
解决方案
下面提供两种可行的修复方式,任选其一即可:
方案1:使用FocusNode监听焦点状态(更推荐)
FocusNode是Flutter原生用于监听焦点变化的类,使用它可以避免WidgetStatesController带来的状态冲突问题:
class CustomTextField extends StatefulWidget { const CustomTextField({super.key}); @override State<CustomTextField> createState() => _CustomTextFieldState(); } class _CustomTextFieldState extends State<CustomTextField> { late final FocusNode _focusNode; bool isFocused = false; @override void initState() { super.initState(); _focusNode = FocusNode() ..addListener(() { // 延迟到当前帧渲染完成后更新状态,避免dirty状态冲突 WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { setState(() { isFocused = _focusNode.hasFocus; }); } }); }); } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(final BuildContext context) { return Padding( padding: isFocused ? const EdgeInsets.all(4) : EdgeInsets.zero, child: TextField( focusNode: _focusNode, ), ); } }
方案2:保留WidgetStatesController,延迟状态更新
如果坚持使用WidgetStatesController,需要通过addPostFrameCallback延迟状态更新,确保组件更新流程完成后再修改状态:
class CustomTextField extends StatefulWidget { const CustomTextField({super.key}); @override State<CustomTextField> createState() => _CustomTextFieldState(); } class _CustomTextFieldState extends State<CustomTextField> { final _widgetStatesController = WidgetStatesController(); bool isFocused = false; @override void initState() { _widgetStatesController.addListener(() { // 延迟到下一帧执行状态更新,避开组件的dirty状态 WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { setState(() { isFocused = _widgetStatesController.value.contains(WidgetState.focused); }); } }); }); super.initState(); } @override void dispose() { _widgetStatesController.dispose(); super.dispose(); } @override Widget build(final BuildContext context) { return Padding( padding: isFocused ? const EdgeInsets.all(4) : EdgeInsets.zero, child: TextField( statesController: _widgetStatesController, ), ); } }
关键修复点说明
WidgetsBinding.instance.addPostFrameCallback:确保状态更新操作在当前帧所有组件重建完成后执行,避免组件处于dirty状态时触发setState的冲突。mounted判断:防止组件已被销毁但回调仍在执行的情况,避免空指针或状态更新报错。- 固定外层Padding容器:相比动态替换TextField的包裹组件,这种方式让组件树结构更稳定,减少不必要的组件重建。
内容的提问来源于stack exchange,提问作者lsaudon
相关产品推荐
相关产品推荐

