I have a Task List View in SwiftUI:
struct TaskListView: View {
@EnvironmentObject var listViewModel: ListViewModel
var body: some View {
ZStack {
if listViewModel.items.isEmpty {
Text("No items")
} else {
List {
ForEach(listViewModel.filteredItems){
item in ListRowView(item: item)
.onTapGesture {
withAnimation(.linear){
listViewModel.updateItem(item: item)
}
}
}
.onDelete(perform: listViewModel.deleteItem)
.onMove(perform: listViewModel.moveItem)
}.listStyle(.sidebar)
}
}
//.navigationTitle()
.navigationBarItems(
leading: EditButton(),
trailing: NavigationLink("Add", destination: AddView()))
}}
struct ListRowView: View {
let item: ItemModel
var body: some View {
HStack {
Image(systemName: item.isCompleted ? "checkmark.circle": "circle")
.foregroundColor(item.isCompleted ? .green: .red)
Text(item.title)
Spacer()
}.font(.body)//.title2)
.padding(.vertical,4)//8)
}}
With the following View Model:
class ListViewModel: ObservableObject {
@Published var items: [ItemModel] = [] {
didSet {
saveItems()
}
}
var filteredItems: [ItemModel] {
items.filter { $0.partOfDay.rawValue.contains("morning")}
}
let itemsKey: String = "items_list"
init() {
getItems()
}
func getItems() {
guard
let data = UserDefaults.standard.data(forKey: itemsKey),
let savedItems = try? JSONDecoder().decode([ItemModel].self, from: data)
else { return }
self.items = savedItems
}
func deleteItem(indexSet: IndexSet) {
items.remove(atOffsets: indexSet)
}
func moveItem(from: IndexSet, to: Int) {
items.move(fromOffsets: from, toOffset: to)
}
func addItem(title: String, partOfDay: PartOfDay) {
let newItem = ItemModel(title: title, partOfDay: partOfDay, isCompleted: false)
items.append(newItem)
}
func updateItem(item: ItemModel) {
if let index = items.firstIndex { (existingItem) -> Bool in
return existingItem.id == item.id
} {
items[index] = item.updateCompletion()
}
}
func saveItems() {
if let encodedData = try? JSONEncoder().encode(items) {
UserDefaults.standard.setValue(encodedData, forKey: itemsKey)
}
}}
I'm trying to re-order filtered items in the list and it doesn't work - items get back to their previous order. If I show all the items from the model without filtering (published property) reordering works correctly. How do I reorder filtered items? (my list has to be grouped by day parts - morning, afternoon, evening and night)
In SwiftUI it's best if your classes are only for model data. For view data use the
Viewstruct, i.e. for the various visual representations of the model data, sorted, moves, filtered etc. To filtered items you just make a computed var:For the no item case a neat trick is an
.overlay, e.g.