Flutter调用setState无法更新AlertDialog内TextFormField的suffixIcon
问题根因
showDialog构建出的弹窗是独立于调用它的父组件树之外的路由页面,你调用父组件DialogPassState的setState只会触发父组件自身的重绘,不会通知弹窗更新UI,所以即使你修改了_showIcons、_startValidateFPass变量,弹窗的输入框图标也不会刷新。- 给
_sPasswordValue赋值能生效,是因为TextEditingController是你在父组件全局持有的,它自身会通知绑定的输入框更新内容,不需要依赖弹窗的UI重绘,这就是两个逻辑表现不一致的原因。
解决方案
改动最小的方式是用 StatefulBuilder 包裹弹窗内容,通过它提供的 setState 方法来触发弹窗内部的UI重绘,具体修改如下:
- 改造
_showDialog方法,给弹窗套上StatefulBuilder - 将原来的状态更新逻辑改用
StatefulBuilder提供的setState执行
修改后的核心代码
_showDialog(BuildContext context) async { var size = MediaQuery.of(context).size; return await showDialog( context: context, builder: (BuildContext context) { // 新增StatefulBuilder包裹AlertDialog return StatefulBuilder( builder: (context, dialogSetState) { // dialogSetState是专门用来更新弹窗UI的方法 return AlertDialog( content: Stack( clipBehavior: Clip.none, children: <Widget>[ Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Padding( padding: EdgeInsets.all(8.0), child: TextFormField( controller: _fPasswordValue, onChanged: (value) { // 改用dialogSetState更新状态,触发弹窗重绘 dialogSetState(() { _startValidateFPass = true; if (value.length >= 8) { _sPasswordValue.text = "test"; _showIcons = true; }else{ _showIcons = false; // 建议补充小于8位的逻辑 } }); }, decoration: InputDecoration( labelText: "New Password", suffixIcon: _showIcons && _startValidateFPass ? _setIcon() :null, ), ), ), Padding( padding: EdgeInsets.all(8.0), child: TextFormField( controller: _sPasswordValue, decoration: InputDecoration( labelText: "Confirm Password", suffixIcon: _showIcons && _startValidateFPass ? _setIcon() :null, ), ), ), // 剩下的按钮代码保持不变即可 Padding( padding: const EdgeInsets.all(8.0), child: Wrap( children: [ OutlinedButton( style: OutlinedButton.styleFrom( fixedSize: Size(size.width / 2 - 10, 20), padding: EdgeInsets.symmetric(horizontal: 50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20)), ), onPressed: () {}, child: Text("CANCEL", style: TextStyle( fontSize: 14, letterSpacing: 2.2, color: Colors.black)), ), OutlinedButton( style: OutlinedButton.styleFrom( fixedSize: Size(size.width / 2 - 10, 20), backgroundColor: Colors.blue[400], primary: Colors.black, padding: EdgeInsets.symmetric(horizontal: 50), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20)), ), onPressed: () {}, child: Text("Save", style: TextStyle( fontSize: 14, letterSpacing: 2.2, color: Colors.black)), ), ], ), ), ], ), ), ], ), ); }, ); }); }
额外优化建议
- 你原来的
_onChange方法可以直接整合到输入框的onChanged回调里,也可以保留方法,把dialogSetState作为参数传进去即可 - 建议补充输入长度小于8位时
_showIcons = false的逻辑,保证回删的时候图标可以正常切换 - 输入框的
onChanged回调已经返回了当前输入的最新值,不需要再读_fPasswordValue.text,直接用回调返回的value即可
内容的提问来源于stack exchange,提问作者Mo7ammed 7amad
相关产品推荐
相关产品推荐

