You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 03:35:17