Flutter实现单选按钮组:修复多选及无法取消选中问题
Flutter 实现单选尺寸按钮组(一行五个)
问题根源分析
原代码的核心问题在于状态管理逻辑错误:
- 把选中状态存在
StatefulWidget的成员变量中,违反了Flutter中Widget不可变的设计原则 - 每个
SizeButton独立维护自身状态,多个按钮之间无法共享状态,导致单选逻辑失效 - 点击时仅修改自身对应的状态变量,无法同步重置其他按钮的选中状态
解决方案:状态提升 + 无状态子组件
将单选组的选中状态统一交给父组件管理,子组件仅负责根据传入的状态渲染样式,并触发点击回调。这样就能保证同一时间只有一个按钮被选中。
重构后的子组件(SizeOptionButton)
改为无状态组件,仅负责渲染和触发回调,状态由父组件传入:
import 'package:flutter/material.dart'; class SizeOptionButton extends StatelessWidget { final String text; final bool isSelected; final VoidCallback onTap; const SizeOptionButton({ super.key, required this.text, required this.isSelected, required this.onTap, }); @override Widget build(BuildContext context) { return InkWell( onTap: onTap, child: Container( width: 40, height: 40, decoration: BoxDecoration( border: Border.all(color: Colors.grey, width: 1), shape: BoxShape.circle, color: isSelected ? Colors.red : Colors.white, ), child: Center( child: Text( text, style: TextStyle( fontSize: 20, color: isSelected ? Colors.white : Colors.black, ), ), ), ), ); } }
父组件使用示例
在父组件中维护当前选中的尺寸,点击按钮时更新状态,同步所有按钮的选中状态:
class SizeSelector extends StatefulWidget { const SizeSelector({super.key}); @override State<SizeSelector> createState() => _SizeSelectorState(); } class _SizeSelectorState extends State<SizeSelector> { // 维护当前选中的尺寸,null表示未选中 String? _selectedSize; // 定义所有尺寸选项 final List<String> _sizes = ['XS', 'S', 'M', 'L', 'XL']; @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: _sizes.map((size) { return SizeOptionButton( text: size, isSelected: _selectedSize == size, onTap: () { setState(() { // 点击已选中的按钮可取消选中(不需要取消则改为`_selectedSize = size`) _selectedSize = _selectedSize == size ? null : size; }); }, ); }).toList(), ); } }
关键优化点
- 状态统一管理:父组件维护
_selectedSize,所有按钮根据这个值判断是否选中,确保单选逻辑绝对正确 - 子组件职责单一:仅负责渲染和触发回调,无内部状态,复用性和可维护性更强
- 灵活控制取消选中:可通过修改点击逻辑,决定是否允许取消已选中的按钮
内容的提问来源于stack exchange,提问作者Numan Ahmad
相关产品推荐
相关产品推荐

