SwiftUI:结构化数组按日期排序并实现日期分组Section Header
解决方案
1. 处理日期转换与排序逻辑
你存储的日期是DD/MM/YYYY格式的字符串,直接按字符串排序会出现逻辑错误(比如14/10/2022的字符串顺序会比15/09/2022靠后,但实际日期更新),所以必须先把字符串转成Date类型实现正确排序。
先给Flight结构体添加计算属性,用于将字符串日期转为Date:
extension Flight { var dateValue: Date? { let formatter = DateFormatter() formatter.dateFormat = "dd/MM/yyyy" formatter.locale = Locale(identifier: "en_US_POSIX") return formatter.date(from: date) } }
修正分组计算属性,同时对分组后的日期按从新到旧排序:
var entryCollatedByDate: [(key: String, value: [Flight])] { // 按日期分组 let grouped = Dictionary(grouping: flightLibrary.testFlight, by: { $0.date }) // 将分组结果转为数组并按日期排序 return grouped.sorted { lhs, rhs in guard let lhsDate = lhs.value.first?.dateValue, let rhsDate = rhs.value.first?.dateValue else { return false } return lhsDate > rhsDate } }
2. 修正主页列表视图
原代码嵌套ForEach都遍历整个数组,导致重复展示内容。现在用分组后的数组构建Section:
ScrollView{ VStack(spacing: 16) { // 遍历分组后的日期组 ForEach(entryCollatedByDate, id: \.key) { group in Section(header: Text(group.key) .font(.title2) .fontWeight(.semibold) .padding(.vertical, 8)) { // 遍历当前日期下的所有航班 ForEach(group.value) { flight in ZStack { RoundedRectangle(cornerRadius: 16, style: .continuous) .fill(Color.white) .shadow(color: Color(.sRGB, white: 0, opacity: 0.2), radius: 4) LogbookCellView(flight: flight) } .padding(.vertical, 8) } } } } .padding(.horizontal, 16) }
3. 可选优化:日期输入合法性校验
保留自动补斜杠逻辑的同时,添加校验确保输入的是有效日期:
TextField("DD/MM/YYYY", text: $flightConfig.date) .padding() .background(.white) .cornerRadius(20.0) .keyboardType(.decimalPad) .onReceive(Just(flightConfig.date)) { inputValue in var filtered = inputValue.filter { $0.isNumber || $0 == "/" } if filtered.count > 10 { filtered = String(filtered.prefix(10)) } // 自动补斜杠 if filtered.count == 2 && !filtered.contains("/") { filtered.append("/") } else if filtered.count == 5 && filtered[filtered.index(filtered.startIndex, offsetBy: 2)] == "/" && !filtered.contains("/", range: filtered.index(filtered.startIndex, offsetBy: 3)..<filtered.endIndex) { filtered.append("/") } self.flightConfig.date = filtered // 校验日期有效性 let formatter = DateFormatter() formatter.dateFormat = "dd/MM/yyyy" if formatter.date(from: filtered) == nil && filtered.count == 10 { // 这里可添加用户提示,比如弹窗或文字提示 print("无效日期") } }
这样就能实现你需要的效果:最新日期的Section在顶部,每个Section下展示对应日期的所有航班;如果需要对同一日期内的航班排序,可在分组时对group.value额外添加排序逻辑。
内容的提问来源于stack exchange,提问作者flyer74
相关产品推荐
相关产品推荐

