如何使用Provider实现单个CheckboxListTile独立选中
问题根源
所有任务项共用了Tasks类里的单个全局布尔值存储勾选状态,没有给每个任务单独维护选中状态,所有TaskTile读取的都是同一个状态值,加上勾选回调是空实现,点击任意复选框自然会触发全选/全不选。
修复方案
1. 重构Tasks状态类
删掉全局共用的勾选布尔值,把任务内容和对应勾选状态绑定存储,新增单个任务的勾选状态切换方法:
class Tasks extends ChangeNotifier { // 每个任务单独存储内容和选中状态,也可以自定义Task实体类替代Map结构 List<Map<String, dynamic>> taskList = [ {'content': 'Buy Milk', 'isChecked': false}, ]; void addTask(String newTask) { taskList.add({'content': newTask, 'isChecked': false}); notifyListeners(); } // 切换指定索引位置任务的勾选状态 void toggleTaskCheck(int index, bool? newValue) { taskList[index]['isChecked'] = newValue ?? false; notifyListeners(); } }
2. 修改TaskList组件
构建列表时透传当前任务的单独状态,补全勾选回调逻辑,点击时只更新对应索引的任务状态:
class TaskList extends StatelessWidget { const TaskList({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Consumer<Tasks>( builder: (context, tasksProvider, child) { return ListView.builder( itemCount: tasksProvider.taskList.length, itemBuilder: (context, index) { final currentTask = tasksProvider.taskList[index]; return TaskTile( listText: currentTask['content'], isChecked: currentTask['isChecked'], functionCallback: (newValue) { tasksProvider.toggleTaskCheck(index, newValue); }, ); }, ); }, ); } }
3. 修改TaskTile组件
不再从Provider全局读取统一的勾选状态,改为接收父组件传入的当前任务专属状态:
class TaskTile extends StatelessWidget { final String? listText; final bool isChecked; final Function(bool?)? functionCallback; const TaskTile({ this.listText, required this.isChecked, this.functionCallback, Key? key }) : super(key: key); @override Widget build(BuildContext context) { return CheckboxListTile( title: Text( listText!, style: TextStyle( decoration: isChecked ? TextDecoration.lineThrough : null, ), ), activeColor: Colors.black, value: isChecked, onChanged: functionCallback, ); } }
核心修改点
- 移除全局共用的单个勾选状态布尔值,每个任务独立维护自己的
isChecked属性 - 补全勾选回调逻辑,点击时只修改当前点击索引对应的任务状态
- 解耦TaskTile和全局勾选状态,组件只接收父组件传入的对应任务状态,避免所有项读同一个值
内容的提问来源于stack exchange,提问作者user16746875
相关产品推荐
相关产品推荐

