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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:35:23