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