显示输入日期并改变方向

Display Entry Date with Change in Orientation

我正在努力获得一个函数来显示日期,仅当它是列表中的第一个日期或与上一个条目日期不同的条目时。除非更改 phone 方向,否则代码似乎可以正常工作。我有一个变量 (listDate) 保存上一个条目日期,它在放入此模块之前被初始化为“”。改变方向是不同的。我已经尝试使用 .onAppear 和 .onChange 的方向数据,但没有任何运气让模块在方向改变时显示列表中带有日期的第一个条目。

感兴趣的函数 (ckDateStatus) 位于此清单的底部。

谢谢你的帮助。

struct WithdrawalView: View {

    @EnvironmentObject var bank: BankWithdrawal

    var body: some View {

        GeometryReader { g in
            VStack (alignment: .leading) {
                List {

                   WDTitleView(g: g)

                   ForEach(bank.wdItem, id: \.id) { item in
                         showSingleWdRow(g: g, item: item )

                   }.onDelete(perform: deleteItem)
                }
            }
        }
    }
}

struct showSingleWdRow: View {

    @EnvironmentObject var bank: BankWithdrawal
    @EnvironmentObject var orientInfo: DeviceOrientation

    var g: GeometryProxy
    var item: WdItem

    var body: some View {

        let entryDate = self.ckDateStatus( cDate: item.wdDate)

        // if withdrawal date is the same as the previous entry skip date and proceed to time
        if !entryDate.isEmpty {
            Text(entryDate)
        }

        // show time, local and home currency amount
        ShowRowTopLine(g:g, item: item)
            .font(.subheadline)

        // show withdrawal location
        if g.size.width > g.size.height {
            Text("\(item.wdCity), \(item.wdState), \(item.wdCountry)")
                
            //}

            //       .onChange(of: orientInfo.orientation == .portrait) { newValue in
            //                bank.listDate = ""
            //        }

            //            if orientInfo.orientation == .portrait {
            //            Text("portrait")
            //            } else {
            //                Text("landscape")
            //            }

        }
    }

    // check if the entry date is the 1st entry in list or the same as previous date
    func ckDateStatus( cDate: Date) -> (String) {
        var outDate: String = ""

        // initialzie the entry date
        let entryDate = cDate.formatted(.dateTime.year().day().month(.wide))

        // if saved date is blank -> no previous entries
        if bank.listDate.isEmpty {
            outDate = entryDate
        }
        else {   // saved date is not blank
            if bank.listDate == entryDate {
                outDate = ""
            }
            else { // date entries different
                outDate = entryDate
            }
        }
        bank.listDate = entryDate

        // outDate returns blank or the current date
        return (outDate)
    }
}

您的方法存在的问题是 SwiftUI 仅重绘必须重绘的单元格。所以在方向改变时,不能保证所有的单元格都会被刷新。

你可以通过添加到你的外部来解决这个问题!查看:

.id(orientInfo)    

这将在 orientInfo 更改时强制重绘视图。

但我会根据 pre-organizing 你的数据建议另一种方法。
您可以创建一个包含您拥有的所有唯一日期的数组,然后按该日期过滤条目。然后可以使用这些数组以您想要的方式显示您的数据——它也可以安全地处理方向变化。

struct ContentView: View {
    
    // dummy data
    let bank: [BankWithdrawal] = [
        BankWithdrawal(wdDate: "22/03/01", wdAmount: 150, wdCity: "New York", wdState: "NY"),
        BankWithdrawal(wdDate: "22/03/01", wdAmount: 100, wdCity: "Miami", wdState: "FL"),
        BankWithdrawal(wdDate: "22/03/02", wdAmount: 300, wdCity: "Orlando", wdState: "FL"),
        BankWithdrawal(wdDate: "22/03/02", wdAmount: 150, wdCity: "S.F.", wdState: "CA"),
        BankWithdrawal(wdDate: "22/03/02", wdAmount: 200, wdCity: "Miami", wdState: "FL"),
        BankWithdrawal(wdDate: "22/03/03", wdAmount: 150, wdCity: "New York", wdState: "NY"),
        BankWithdrawal(wdDate: "22/03/04", wdAmount: 500, wdCity: "S.F.", wdState: "CA"),
        BankWithdrawal(wdDate: "22/03/04", wdAmount: 150, wdCity: "Miami", wdState: "FL"),
        BankWithdrawal(wdDate: "22/03/04", wdAmount: 250, wdCity: "New York", wdState: "NY"),
        BankWithdrawal(wdDate: "22/03/05", wdAmount: 150, wdCity: "S.F.", wdState: "CA")
    ]
    
    // creates a list of unique date entries
    // (goes through all elements, saves them in a set, checks if already in set)
    var uniqueBankDates: [BankWithdrawal] {
        var seen: Set<String> = []
        return bank.filter { seen.insert([=11=].wdDate).inserted }
    }
    
    // filters entries for the given date
    func bankEntries(for date: String) -> [BankWithdrawal] {
        return bank.filter { [=11=].wdDate == date }
    }
    
    var body: some View {
        List {
            // outer ForEach with unique dates
            ForEach(uniqueBankDates) { dateItem in
                Section {
                    // inner ForEach with items of this date
                    ForEach(bankEntries(for: dateItem.wdDate)) { item in
                        Text("$\(item.wdAmount, specifier: "%.2f")  \(item.wdCity), \(item.wdState)")
                    }
                } header: {
                    Text(dateItem.wdDate)
                }
            }
        }
    }
}

struct BankWithdrawal: Identifiable {
    let id = UUID()
    var wdDate: String
    var wdAmount: Double
    var wdCity: String
    var wdState: String
    var wdCountry: String = "USA"
}

编辑: 使用 Date() 时,您可以这样做:

struct ContentView: View {
    
    // dummy data
    let bank: [BankWithdrawal] = [
        BankWithdrawal(wdDate: Date(), wdAmount: 150, wdCity: "New York", wdState: "NY"),
        BankWithdrawal(wdDate: Date(), wdAmount: 100, wdCity: "Miami", wdState: "FL"),
        BankWithdrawal(wdDate: Date(), wdAmount: 300, wdCity: "Orlando", wdState: "FL"),
        BankWithdrawal(wdDate: Date(), wdAmount: 150, wdCity: "S.F.", wdState: "CA"),
        BankWithdrawal(wdDate: Date(), wdAmount: 200, wdCity: "Miami", wdState: "FL"),
        BankWithdrawal(wdDate: Date(), wdAmount: 150, wdCity: "New York", wdState: "NY"),
        BankWithdrawal(wdDate: Date() + 60*60*24*1, wdAmount: 500, wdCity: "S.F.", wdState: "CA"),
        BankWithdrawal(wdDate: Date() + 60*60*24*1, wdAmount: 150, wdCity: "Miami", wdState: "FL"),
        BankWithdrawal(wdDate: Date() + 60*60*24*1, wdAmount: 250, wdCity: "New York", wdState: "NY"),
        BankWithdrawal(wdDate: Date() + 60*60*24*1, wdAmount: 150, wdCity: "S.F.", wdState: "CA")
    ]
    
    // creates a list of unique date entries
    // (goes through all elements, saves them in a set, checks if already in set)
    var uniqueBankDates: [String] {
        var seen: Set<String> = []
        return bank.filter { seen.insert([=12=].wdDate.formatted(date: .abbreviated, time: .omitted)).inserted }
        .map {[=12=].wdDate.formatted(date: .abbreviated, time: .omitted) }
    }
    
    // filters entries for the given date
    func bankEntries(for date: String) -> [BankWithdrawal] {
        return bank.filter { [=12=].wdDate.formatted(date: .abbreviated, time: .omitted) == date }
    }
    
    var body: some View {
        List {
            // outer ForEach with unique dates
            ForEach(uniqueBankDates, id: \.self) { dateItem in
                Section {
                    // inner ForEach with items of this date
                    ForEach(bankEntries(for: dateItem)) { item in
                        Text("$\(item.wdAmount, specifier: "%.2f")  \(item.wdCity), \(item.wdState)")
                    }
                } header: {
                    Text("\(dateItem)")
                }
            }
        }
    }
}

struct BankWithdrawal: Identifiable {
    let id = UUID()
    var wdDate: Date
    var wdAmount: Double
    var wdCity: String
    var wdState: String
    var wdCountry: String = "USA"
}