Flutter中如何实现跨Stateful Widget的复选框全选/反选
Flutter 实现全选与列表项复选框联动(无第三方依赖)
核心思路:状态提升
由于全选框和列表项是独立的Stateful Widget,需将选中状态的控制权统一移到它们的共同父Widget,通过回调函数实现状态同步。
1. 在父Widget中统一管理状态
定义两个核心状态,负责全选状态和所有列表项的选中状态:
class ParentPage extends StatefulWidget { const ParentPage({super.key}); @override State<ParentPage> createState() => _ParentPageState(); } class _ParentPageState extends State<ParentPage> { // 模拟业务列表数据,替换为你的实际数据 final List<String> _listItems = ['Item 1', 'Item 2', 'Item 3', 'Item 4']; bool _isSelectAll = false; late List<bool> _itemCheckedStates; @override void initState() { super.initState(); // 初始化所有列表项为未选中状态 _itemCheckedStates = List.filled(_listItems.length, false); } // 后续逻辑方法写在此处 }
2. 改造全选Checkbox的回调逻辑
更新全选框的onChanged方法,点击时同步所有列表项的选中状态:
// 父Widget中构建全选Row的代码 Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Transform.scale( scale: 1.3, child: Checkbox( side: MaterialStateBorderSide.resolveWith( (Set<MaterialState> states) { if (states.contains(MaterialState.selected)) { return const BorderSide(width: 2, color: Color(0xff34495E)); } return const BorderSide(width: 1, color: Color(0xffB0BEC1)); }, ), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), activeColor: const Color(0xff34495E), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity(horizontal: -4, vertical: -4), value: _isSelectAll, onChanged: (value) { setState(() { _isSelectAll = value ?? false; // 同步所有列表项的选中状态与全选框一致 _itemCheckedStates = List.filled(_listItems.length, _isSelectAll); }); }, ), ), const SizedBox(width: 10), Text( 'Select all', style: GoogleFonts.poppins( color: Colors.black87, fontSize: 12, fontWeight: FontWeight.w400), ), ], )
3. 改造列表项Widget,接收外部状态与回调
将列表项的选中状态改为从父Widget传入,同时添加回调函数通知父Widget更新状态:
// 改造后的列表项Widget class ListItemWidget extends StatefulWidget { final String title; final bool isChecked; final ValueChanged<bool> onCheckedChanged; final bool isCheckboxVisible; const ListItemWidget({ super.key, required this.title, required this.isChecked, required this.onCheckedChanged, required this.isCheckboxVisible, }); @override State<ListItemWidget> createState() => _ListItemWidgetState(); } class _ListItemWidgetState extends State<ListItemWidget> { @override Widget build(BuildContext context) { return ListTile( title: Text(widget.title), leading: Visibility( visible: widget.isCheckboxVisible, child: Transform.scale( scale: 1.3, child: Checkbox( side: MaterialStateBorderSide.resolveWith( (Set<MaterialState> states) { if (states.contains(MaterialState.selected)) { return const BorderSide(width: 2, color: Color(0xff34495E)); } return const BorderSide(width: 1, color: Color(0xffB0BEC1)); }, ), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), activeColor: const Color(0xff34495E), value: widget.isChecked, onChanged: (value) { widget.onCheckedChanged(value ?? false); }, ), ), ), ); } }
4. 在父Widget中构建列表,绑定状态与回调
在父Widget的build方法中构建列表,传递每个列表项的状态和回调,同时处理单个列表项点击后更新全选状态:
// 父Widget中构建列表的代码 ListView.builder( itemCount: _listItems.length, itemBuilder: (context, index) { return ListItemWidget( title: _listItems[index], isChecked: _itemCheckedStates[index], isCheckboxVisible: true, // 替换为你的controller.isCheboxVisible.value onCheckedChanged: (value) { setState(() { _itemCheckedStates[index] = value; // 检查所有列表项是否都选中,更新全选状态 _isSelectAll = _itemCheckedStates.every((item) => item); }); }, ); }, )
动态列表优化(可选)
如果列表数据是动态加载的(如分页),需在数据更新时同步更新选中状态列表:
// 更新列表数据时调用 void updateListData(List<String> newItems) { setState(() { _listItems = newItems; // 保留已有选中状态,新添加项默认未选中 _itemCheckedStates = [ ..._itemCheckedStates.take(newItems.length), ...List.filled(newItems.length - _itemCheckedStates.length, false) ]; // 重新校验全选状态 _isSelectAll = _itemCheckedStates.every((item) => item); }); }
内容的提问来源于stack exchange,提问作者tesseract
相关产品推荐
相关产品推荐

