Home > Software design >  How to sort List ForEach Swiftui
How to sort List ForEach Swiftui

Time:01-12

Hi there

I'm newbie for SwiftUI, and I want to sort the "expireDate" , then use forEach to display the view according to the expireDate, how to???

sorry for my messy code, coding is really not easy.

will be much appreciate if someone can help

Here is the data

import Foundation

struct CardData: Identifiable, Codable {
    
    let id: UUID
    var cardName: String
    var cardNumber: String
    var expireDate: Date
    var theme: Theme
    var history: [History] = []
    
    init(id: UUID = UUID(), cardName: String, cardNumber: String, expireDate: Date, theme: Theme) {
        self.id = id
        self.cardName = cardName
        self.cardNumber = cardNumber
        self.expireDate = expireDate
        self.theme = theme
    }
}

extension CardData {
    struct Data {
        var cardName: String = ""
        var cardNumber: String = ""
        var expireDate: Date = Date.now
        var theme: Theme = .orange
    }
    var data: Data {
        Data(cardName: cardName, cardNumber: cardNumber, expireDate: expireDate, theme: theme)
    }
    
    mutating func update(from data: Data) {
        cardName = data.cardName
        cardNumber = data.cardNumber
        expireDate = data.expireDate
        theme = data.theme
    }
    
    init(data: Data) {
        cardName = data.cardName
        cardNumber = data.cardNumber
        expireDate = data.expireDate
        theme = data.theme
        id = UUID()
    }
}

And here is the view

import SwiftUI

struct CardView: View {
    
    @Binding var datas: [CardData]
    @Environment(\.scenePhase) private var scenePhase
    @State private var isPresentingNewCardView = false
    @State private var newCardData = CardData.Data()
    let saveAction: () -> Void
    @EnvironmentObject var launchScreenManager: LaunchScreenManager
    @State private var confirmationShow = false
    
    var body: some View {
        List {
            ForEach($datas) { $data in
                NavigationLink(destination: DetailView(cardData: $data)){
                    CardDataView(cardData: data)
                }
                .listRowBackground(data.theme.mainColor)
            }
            .onDelete(perform: deleteItems)
        }
        .navigationTitle("Expiry Date")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            Button(action: {
                isPresentingNewCardView = true
            }) {
                Image(systemName: "plus")
            }
            .accessibilityLabel("New data")
        }
        .sheet(isPresented: $isPresentingNewCardView) {
            NavigationView {
                DetailEditView(data: $newCardData)
                    .toolbar {
                        ToolbarItem(placement: .cancellationAction) {
                            Button("Dismiss") {
                                isPresentingNewCardView = false
                                newCardData = CardData.Data()
                            }
                        }
                        ToolbarItem(placement: .confirmationAction) {
                            Button("Add") {
                                let newData = CardData(data: newCardData)
                                datas.append(newData)
                                isPresentingNewCardView = false
                                newCardData = CardData.Data()
                            }
                        }
                    }
            }
            
        }
        .onChange(of: scenePhase) { phase in
            if phase == .inactive { saveAction() }
        }
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now()   2) {
                launchScreenManager.dismiss()
            }
        }
    }
    
    func deleteItems(at offsets: IndexSet) {
        datas.remove(atOffsets: offsets)
    }
}

Hi there

I'm newbie for SwiftUI, and I want to sort the "expireDate" , then use forEach to display the view according to the expireDate, how to??? sorry for my messy code, coding is really not easy. will be much appreciate if someone can help

CodePudding user response:

You can sort the datas in place, before you use it in the ForEach, when you create the datas for example. Like this: datas.sort(by: { $0.expireDate > $1.expireDate}).

Or

you can sort the datas just in the ForEach, like this, since you have bindings, ForEach($datas.sorted(by: { $0.expireDate.wrappedValue > $1.expireDate.wrappedValue})) { $data ...}

Note with this ForEach($datas.sorted(by: ...), when you do your func deleteItems(at offsets: IndexSet), you will have to get the index in the sorted array, and delete the equivalent in the original one.

EDIT-1:

updated func deleteItems:

func deleteItems(at offsets: IndexSet) {
    let sortedArr = datas.sorted(by: { $0.expireDate > $1.expireDate})
    for ndx in offsets {
        if let cardIndex = datas.firstIndex(where: { $0.id == sortedArr[ndx].id }) {
            datas.remove(at: cardIndex)
        }
    }
}

Note you may want to put let sortedArr = datas.sorted(by: { $0.expireDate > $1.expireDate}) somewhere else (eg. .onAppear) instead of evaluating this, every time you use deleteItems

  • Related