Flutter带预约按钮的特殊时段预约表格开发求助
解决方案:Flutter 时段预约表格实现
核心逻辑梳理
预约规则核心:
- 每个时段为可交互的预约单元
- 存在已预约时段时,新预约仅能选择该已预约时段之前的连续空闲时段或之后的连续空闲时段,不可跨已预约时段预约
实现步骤
1. 定义数据模型
先构建时段与预约状态的数据结构:
// 时段模型 class TimeSlot { final String id; final String timeRange; // 示例:"09:00-09:30" bool isBooked; bool isAvailable; // 标记当前时段是否可预约 TimeSlot({ required this.id, required this.timeRange, this.isBooked = false, this.isAvailable = true, }); }
2. 实现可预约状态计算函数
这是核心逻辑,根据已预约位置更新所有时段的可预约状态:
void updateAvailableSlots(List<TimeSlot> slots) { // 筛选出所有已预约时段的索引 final bookedIndices = slots.asMap().entries .where((entry) => entry.value.isBooked) .map((entry) => entry.key) .toList(); if (bookedIndices.isEmpty) { // 无预约时所有时段均可预约 for (var slot in slots) { slot.isAvailable = true; } return; } // 获取首尾已预约时段的索引 final firstBookedIdx = bookedIndices.first; final lastBookedIdx = bookedIndices.last; // 首预约时段之前的时段设为可预约 for (int i = 0; i < firstBookedIdx; i++) { slots[i].isAvailable = true; } // 尾预约时段之后的时段设为可预约 for (int i = lastBookedIdx + 1; i < slots.length; i++) { slots[i].isAvailable = true; } // 已预约区间内的时段设为不可预约 for (int i = firstBookedIdx; i <= lastBookedIdx; i++) { slots[i].isAvailable = false; } }
3. 构建预约表格UI
用GridView实现灵活的时段网格展示(也可替换为DataTable实现标准表格样式):
Widget buildTimeSlotGrid(List<TimeSlot> slots) { return GridView.builder( shrinkWrap: true, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, // 每行显示4个时段 crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemCount: slots.length, itemBuilder: (context, index) { final slot = slots[index]; return ElevatedButton( onPressed: slot.isAvailable ? () { // 触发预约操作,更新状态 setState(() { slot.isBooked = true; updateAvailableSlots(slots); }); } : null, style: ElevatedButton.styleFrom( backgroundColor: slot.isBooked ? Colors.redAccent : slot.isAvailable ? Colors.greenAccent : Colors.grey, ), child: Text(slot.timeRange), ); }, ); }
4. 页面状态管理
在StatefulWidget中初始化时段列表并整合UI:
class BookingTableScreen extends StatefulWidget { const BookingTableScreen({super.key}); @override State<BookingTableScreen> createState() => _BookingTableScreenState(); } class _BookingTableScreenState extends State<BookingTableScreen> { late List<TimeSlot> timeSlots; @override void initState() { super.initState(); // 初始化时段列表(示例为9:00-12:00的半小时间隔时段) timeSlots = [ TimeSlot(id: "1", timeRange: "09:00-09:30"), TimeSlot(id: "2", timeRange: "09:30-10:00"), TimeSlot(id: "3", timeRange: "10:00-10:30"), TimeSlot(id: "4", timeRange: "10:30-11:00"), TimeSlot(id: "5", timeRange: "11:00-11:30"), TimeSlot(id: "6", timeRange: "11:30-12:00"), ]; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("时段预约")), body: Padding( padding: const EdgeInsets.all(16.0), child: buildTimeSlotGrid(timeSlots), ), ); } }
扩展说明
- 若需支持多个非连续已预约时段,可修改
updateAvailableSlots函数,遍历所有时段标记可预约区间,确保新预约无法跨已预约块选择 - 如需持久化预约数据,可结合
SharedPreferences存储本地状态,或对接后端API实现跨设备同步 - UI样式可按需调整,比如添加日期筛选、时段详情弹窗等功能
内容的提问来源于stack exchange,提问作者Shajko
相关产品推荐
相关产品推荐

