如何用ValueListenableBuilder和ValueNotifier实现单选按钮控制表单字段显隐并解决双击问题
解决方案:用ValueNotifier + ValueListenableBuilder实现单选联动表单显示
直接上步骤和代码,解决你遇到的双击生效问题:
- 定义ValueNotifier替代原状态变量
在你的State类里声明一个ValueNotifier<bool>,用来精准控制表单的显示状态,替换原来的_isVisible:
final ValueNotifier<bool> _showFormField = ValueNotifier<bool>(false);
- 修改单选按钮的回调逻辑
更新单选按钮的onChanged方法,直接通过_showFormField更新状态,无需调用setState:
RadioListTile<SingingCharacter>( title: const Text('需要填写里程'), value: SingingCharacter.checked, groupValue: _character, onChanged: (SingingCharacter? value) { _character = value!; // 选中该选项时显示表单 _showFormField.value = true; }, ), RadioListTile<SingingCharacter>( title: const Text('不需要填写里程'), value: SingingCharacter.unchecked, groupValue: _character, onChanged: (SingingCharacter? value) { _character = value!; // 选中该选项时隐藏表单 _showFormField.value = false; }, ),
- 用ValueListenableBuilder包裹表单组件
把原来的Visibility嵌套进ValueListenableBuilder,监听_showFormField的变化,实现即时的显示/隐藏切换:
ValueListenableBuilder<bool>( valueListenable: _showFormField, builder: (context, isVisible, child) { return Visibility( visible: isVisible, child: child!, ); }, // 将表单容器作为child传入,避免状态变化时重复创建组件 child: Container( width: 396, height: 73, decoration: BoxDecoration( boxShadow: [ BoxShadow( color: Color(0xff000000).withOpacity(0.08), offset: Offset(0, 2), blurRadius: 6, ), ], color: Color(0xffFAFAFA), borderRadius: BorderRadius.circular(17)), child: Padding( padding: const EdgeInsets.fromLTRB(15, 25, 0, 0), child: TextFormField( enabled: _character == SingingCharacter.unchecked ? true : false, onSaved: (Value) => print('hello'), decoration: InputDecoration( hintStyle: TextStyle( fontFamily: "Proxima Nova", fontWeight: FontWeight.w300, ), border: InputBorder.none, labelStyle: TextStyle( color: Color(0xffFAFAFA), ), ), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r"[0-9]+|\s")) ], controller: kiloMeter, validator: (value) { if (value != null && value.isEmpty) { return "请输入里程数"; } // 原代码中`value != 1000`是字符串与数字比较,逻辑有误,若需判断数值请自行调整 return null; }, ), ), ), ),
- 释放资源避免内存泄漏
在State的dispose方法中释放ValueNotifier和文本控制器:
@override void dispose() { _showFormField.dispose(); kiloMeter.dispose(); super.dispose(); }
为什么能解决双击问题?
原来的setState会触发整个页面的重建,可能导致状态更新延迟;而ValueListenableBuilder只会监听指定的状态变量变化,触发局部组件重建,状态更新更精准及时,不会出现双击才生效的情况。
内容的提问来源于stack exchange,提问作者WonderingDino
相关产品推荐
相关产品推荐

