Flutter实现横向列表连续选中功能(禁止跳选)技术咨询
解决方案
1. 修改状态变量
将原有的单选索引变量替换为记录连续选中区间的变量,同时新增存储选中时间段的列表:
// 记录连续选中区间的起始、结束索引 int _selectedStart = -1; int _selectedEnd = -1; // 存储所有选中的时间段 List<String> _selectedTimeSlots = [];
2. 重构点击事件逻辑
在InkWell的onTap回调中添加连续选中的判断规则,同时处理跳选的错误提示:
onTap: () { setState(() { // 无选中项时,直接选中当前索引 if (_selectedStart == -1) { _selectedStart = index; _selectedEnd = index; _selectedTimeSlots = [dataSchedule[index]['time_slot']]; } else { // 点击选中区间的下一项:向右扩展选中范围 if (index == _selectedEnd + 1) { _selectedEnd = index; _selectedTimeSlots.add(dataSchedule[index]['time_slot']); } // 点击选中区间的上一项:向左扩展选中范围(不需要可删除此分支) else if (index == _selectedStart - 1) { _selectedStart = index; _selectedTimeSlots.insert(0, dataSchedule[index]['time_slot']); } // 点击已选中区间内的项:截断选中范围到当前项 else if (index >= _selectedStart && index <= _selectedEnd) { _selectedEnd = index; _selectedTimeSlots = _selectedTimeSlots.sublist(0, index - _selectedStart + 1); } // 跳选情况:弹出错误提示 else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('只能连续从左到右选择时间段,不能跳选')), ); return; } } }); },
3. 更新UI选中样式
修改BoxDecoration的边框颜色判断逻辑,判断当前索引是否处于选中区间内:
border: Border.all( color: scheduleField == "field require" ? Colors.red : (index >= _selectedStart && index <= _selectedEnd) ? colorBlue : Colors.grey[200]!, width: 2, ),
完整改造后的代码
// 状态变量 int _selectedStart = -1; int _selectedEnd = -1; List<String> _selectedTimeSlots = []; // 列表组件 Container( height: 50, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: dataSchedule == null ? 0 : dataSchedule.length, itemBuilder: (BuildContext context, int index) { return InkWell( onTap: () { setState(() { if (_selectedStart == -1) { _selectedStart = index; _selectedEnd = index; _selectedTimeSlots = [dataSchedule[index]['time_slot']]; } else { if (index == _selectedEnd + 1) { _selectedEnd = index; _selectedTimeSlots.add(dataSchedule[index]['time_slot']); } else if (index == _selectedStart - 1) { _selectedStart = index; _selectedTimeSlots.insert(0, dataSchedule[index]['time_slot']); } else if (index >= _selectedStart && index <= _selectedEnd) { _selectedEnd = index; _selectedTimeSlots = _selectedTimeSlots.sublist(0, index - _selectedStart + 1); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('只能连续从左到右选择时间段,不能跳选')), ); return; } } }); }, child: Container( padding: EdgeInsets.all(0), child: Card( color: Colors.white, elevation: 0, semanticContainer: true, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), ), child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(3.0), border: Border.all( color: scheduleField == "field require" ? Colors.red : (index >= _selectedStart && index <= _selectedEnd) ? colorBlue : Colors.grey[200]!, width: 2, ), ), padding: EdgeInsets.all(10), child: Center( child: Text( dataSchedule[index]['time_slot'], style: TextStyle( fontFamily: 'Montserrat', color: colorBlack, fontWeight: FontWeight.bold, fontSize: 15, ), textAlign: TextAlign.center, ), ), ), ), ), ); }, ), );
逻辑说明
- 初始无选中项时,点击任意项直接选中该单个项作为起始区间。
- 支持向右扩展选中范围(点击当前选中最右侧的下一项)。
- 可选支持向左扩展范围(不需要可删除对应分支代码)。
- 点击已选中区间内的项时,自动截断选中范围到当前点击项。
- 出现跳选操作时,通过SnackBar提示用户错误规则。
内容的提问来源于stack exchange,提问作者YourDeveloper
相关产品推荐
相关产品推荐

