【发布时间】:2021-08-01 09:02:17
【问题描述】:
在待办事项列表中,我在更新列表时遇到了 2 个问题。
-
删除列表中的项目时,它会飞到随机位置。 (故障)。我想这与独特的
identifier正确处理有关 -
勾选列表中的项目时,不会更改部分。视图仅在添加新项目后更新。
- 此外,也许您知道如何在没有更多项目时隐藏部分,并在添加任务时重新出现。
列表视图
struct ContentView: View {
@ObservedObject var listViewModel = ListViewModel()
@State var newItem = ""
var body: some View {
VStack {
Form {
// To-do section
Section(header: Text("New")) {
ForEach(listViewModel.itemCellViewModels) { itemCellViewModel in
if itemCellViewModel.item.accomplished == false {
ItemCellView(itemCellViewModel: itemCellViewModel)
}
}.onDelete(perform: { indexSet in
//remove item from the shopping list
self.listViewModel.itemCellViewModels.remove(atOffsets: indexSet)
print(indexSet)
})
.onDelete(perform: listViewModel.removeRows)
}
// Accomplished section
Section(header: Text("Done")) {
ForEach(listViewModel.itemCellViewModels.indices, id: \.self) { index in
if listViewModel.itemCellViewModels[index].item.accomplished == true {
ItemCellView(itemCellViewModel: listViewModel.itemCellViewModels[index])
}
}.onDelete(perform: listViewModel.removeRows)
}
}
TextField("Enter item here", text: $newItem) { _ in
} onCommit: {
self.listViewModel.addItem(item: Item(productName: newItem, accomplished: false))
newItem = ""
}
.autocapitalization(.none)
.padding()
.border(Color.blue)
.padding()
}
// update ViewModel with placeholder data
.onAppear(perform: {self.listViewModel.itemCellViewModels.append(contentsOf: placeholderItems)})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
var placeholderItems = [
ItemViewModel(item: Item(productName: "1", accomplished: false)),
ItemViewModel(item: Item(productName: "2", accomplished: false)),
ItemViewModel(item: Item(productName: "3", accomplished: false)),
ItemViewModel(item: Item(productName: "4", accomplished: false)),
ItemViewModel(item: Item(productName: "5", accomplished: false)),
ItemViewModel(item: Item(productName: "6", accomplished: true)),
ItemViewModel(item: Item(productName: "7", accomplished: true)),
ItemViewModel(item: Item(productName: "8", accomplished: true)),
ItemViewModel(item: Item(productName: "9", accomplished: true)),
ItemViewModel(item: Item(productName: "10", accomplished: true))
]
/// The rest of the code
// Reusable View for Cells
struct ItemCellView: View {
@ObservedObject var itemCellViewModel: ItemViewModel
// send an item (doesn't return anything)
var onCommit: (Item) -> (Void) = { _ in }
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(itemCellViewModel.item.productName)
}
Spacer()
Button(action: {
itemCellViewModel.item.accomplished.toggle()
}, label: {
Image(systemName: (itemCellViewModel.item.accomplished ? "checkmark.square" : "square"))
.resizable()
.frame(width: 25, height: 25)
})
}.opacity(itemCellViewModel.item.accomplished ? 0.3 : 1)
}
}
import Foundation
import Combine
class ItemViewModel: ObservableObject, Identifiable {
@Published var item: Item
var id = UUID()
@Published var items: [Item] = []
@Published var completionStateIconName = ""
private var cancellables = Set<AnyCancellable>()
init(item: Item) {
self.item = item
$item
.map { item in
item.accomplished ? "checkmark.square" : "square"
}
.assign(to: \.completionStateIconName, on: self)
.store(in: &cancellables) // <- for memory management purposes
}
}
class ListViewModel: ObservableObject {
@Published var itemCellViewModels = [ItemViewModel]()
private var cancellables = Set<AnyCancellable>()
func addItem(item: Item) {
let itemVM = ItemViewModel(item: item)
self.itemCellViewModels.append(itemVM)
}
func removeRows(at offsets: IndexSet) {
itemCellViewModels.remove(atOffsets: offsets)
}
}
// Model
struct Item: Identifiable {
var id = UUID()
var productName: String
var accomplished: Bool
}
单元格的可重用视图
struct ItemCellView: View {
@ObservedObject var itemCellViewModel: ItemViewModel
// send an item (doesn't return anything)
var onCommit: (Item) -> (Void) = { _ in }
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(itemCellViewModel.item.productName)
}
Spacer()
Button(action: {
itemCellViewModel.item.accomplished.toggle()
}, label: {
Image(systemName: (itemCellViewModel.item.accomplished ? "checkmark.square" : "square"))
.resizable()
.frame(width: 25, height: 25)
})
}.opacity(itemCellViewModel.item.accomplished ? 0.3 : 1)
}
}
ItemViewModel
import Foundation
import Combine
class ItemViewModel: ObservableObject, Identifiable {
@Published var item: Item
var id = UUID()
@Published var items: [Item] = []
@Published var completionStateIconName = ""
private var cancellables = Set<AnyCancellable>()
init(item: Item) {
self.item = item
$item
.map { item in
item.accomplished ? "checkmark.square" : "square"
}
.assign(to: \.completionStateIconName, on: self)
.store(in: &cancellables) // <- for memory management purposes
}
}
ListViewModel
import Foundation
import Combine
class ListViewModel: ObservableObject {
@Published var itemCellViewModels = [ItemViewModel]()
private var cancellables = Set<AnyCancellable>()
func addItem(item: Item) {
let itemVM = ItemViewModel(item: item)
self.itemCellViewModels.append(itemVM)
}
func removeRows(at offsets: IndexSet) {
itemCellViewModels.remove(atOffsets: offsets)
}
}
型号
struct Item: Identifiable {
var id = UUID()
var productName: String
var accomplished: Bool
}
【问题讨论】:
-
您会将
productName更改为什么以获得更好的可读性? mbItem....value/name/description? -
我建议
name
标签: listview swiftui swiftui-list