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

Flutter中如何用动态数量List实现GridView时间槽单选变色?

解决Flutter GridView时间槽单选变色问题

能不能用变量替代常量初始化选中状态列表?

完全可以,不需要固定常量,直接用统计得到的总槽位数变量来处理就行,甚至更推荐用单个变量记录选中索引的方式——逻辑更清晰,还能节省内存。

解决方案1:单个变量记录选中索引(推荐)

不需要维护长度等于总槽位数的List,只用一个selectedIndex变量记录当前选中的槽位索引,UI根据索引是否匹配切换颜色,点击时直接更新索引就能自动取消其他槽位的选中状态。

import 'package:flutter/material.dart';

class TimeSlotPicker extends StatefulWidget {
  final int totalSlots; // 直接传入统计得到的总槽位数变量

  const TimeSlotPicker({super.key, required this.totalSlots});

  @override
  State<TimeSlotPicker> createState() => _TimeSlotPickerState();
}

class _TimeSlotPickerState extends State<TimeSlotPicker> {
  int? selectedIndex; // null表示未选中任何槽位

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      padding: const EdgeInsets.all(16),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        crossAxisSpacing: 8,
        mainAxisSpacing: 8,
      ),
      itemCount: widget.totalSlots,
      itemBuilder: (context, index) {
        bool isSelected = selectedIndex == index;
        return GestureDetector(
          onTap: () {
            setState(() {
              selectedIndex = index; // 点击更新选中索引,自动取消其他选中
            });
          },
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: isSelected ? Colors.blue : Colors.grey.shade200,
              borderRadius: BorderRadius.circular(8),
            ),
            child: Text(
              '槽位 ${index + 1}',
              style: TextStyle(
                color: isSelected ? Colors.white : Colors.black87,
                fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
              ),
            ),
          ),
        );
      },
    );
  }
}

// 使用示例:直接传入统计好的槽位数
// TimeSlotPicker(totalSlots: 15)

解决方案2:动态生成List管理选中状态

如果坚持要用List维护选中状态,也可以用变量初始化,不需要常量。注意如果总槽位数可能动态变化,要重写didUpdateWidget方法更新List。

import 'package:flutter/material.dart';

class TimeSlotPicker extends StatefulWidget {
  final int totalSlots;

  const TimeSlotPicker({super.key, required this.totalSlots});

  @override
  State<TimeSlotPicker> createState() => _TimeSlotPickerState();
}

class _TimeSlotPickerState extends State<TimeSlotPicker> {
  late List<bool> selectedSlots;

  @override
  void initState() {
    super.initState();
    // 用传入的totalSlots变量初始化选中列表,默认全未选中
    selectedSlots = List.generate(widget.totalSlots, (_) => false);
  }

  // 若总槽位数可能动态变化,更新组件时同步更新选中列表
  @override
  void didUpdateWidget(covariant TimeSlotPicker oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.totalSlots != widget.totalSlots) {
      setState(() {
        selectedSlots = List.generate(widget.totalSlots, (_) => false);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      padding: const EdgeInsets.all(16),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
        crossAxisSpacing: 8,
        mainAxisSpacing: 8,
      ),
      itemCount: widget.totalSlots,
      itemBuilder: (context, index) {
        bool isSelected = selectedSlots[index];
        return GestureDetector(
          onTap: () {
            setState(() {
              // 先取消所有槽位的选中状态
              for (int i = 0; i < selectedSlots.length; i++) {
                selectedSlots[i] = false;
              }
              // 再选中当前槽位
              selectedSlots[index] = true;
            });
          },
          child: Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              color: isSelected ? Colors.blue : Colors.grey.shade200,
              borderRadius: BorderRadius.circular(8),
            ),
            child: Text(
              '槽位 ${index + 1}',
              style: TextStyle(
                color: isSelected ? Colors.white : Colors.black87,
                fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
              ),
            ),
          ),
        );
      },
    );
  }
}

方案对比

  • 方案1逻辑简单、内存开销小,完全适配单选场景,优先推荐。
  • 方案2适合后续可能扩展为多选的场景,但单选下没必要额外遍历List取消选中状态。

内容的提问来源于stack exchange,提问作者Muhammad Umar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 16:57:15