我有一个@Environment,它存储所有共享数据供我查看。我的一种观点使用其变量之一来呈现包含可折叠项的列表。为了使列表可折叠,我使用@State是true还是false展开可折叠的内容,在此列表中,我希望用户可以删除其项目,因此我创建了一个函数,用于从@Environment中的变量中删除项目并更新视图。问题在于State更改为其默认值,并且Expanded list变成折叠状态。我想知道如何保留先前的状态,或者告诉我的观点是仅重新渲染实际更改的部分。
这是我的环境对象。我所有的观点都同意这一点。
class GlobalData:ObservableObject {
@Published var SpoonData: [Item?] = []
@Published var currentTab: Int = 0
func deleteSpoonData(at offsets: IndexSet) {
self.SpoonData.remove(atOffsets: offsets)
}
func addSpoonData(item: Item, itemList: Items){
let exists = SpoonData.firstIndex(where: {$0?.ItemId == item.ItemId})
var rt = item
rt.ItemList = itemList
if exists == nil {
self.SpoonData.append(rt)
}
}
func deleteProductFromItemList(product: Product, itemId: Int) {
let fatherIndex = self.SpoonData.firstIndex { item -> Bool in
item?.ItemId == itemId
}
let childIndex = (self.SpoonData[fatherIndex!]?.ItemList?.ItemList?.firstIndex(where: { productfiltered -> Bool in
productfiltered?.EntryID == product.EntryID
}))!
print(self.SpoonData[fatherIndex!]?.ItemList?.ItemList![childIndex])
self.SpoonData[fatherIndex!]?.ItemList?.ItemList!.remove(at: childIndex)
}
}
这是显示列表的视图。
struct SpoonListItemView: View {
private let viewModel: SpoonListItemViewModel
@State private var isCollapsed: Bool = false
init(viewModel: SpoonListItemViewModel) {
self.viewModel = viewModel
}
var body: some View {
VStack {
VStack {
HStack(alignment: .top) {
if self.viewModel.ItemType == 1 {
AsyncImage(url: viewModel.ItemImageUrl, size: CGSize(width: 45.0, height: 45.0), contentMode: .fit)
.clipShape(Rectangle())
} else {
AsyncImage(url: viewModel.ItemImageUrl, size: CGSize(width: 45.0, height: 45.0), contentMode: .fit)
.clipShape(Circle())
}
VStack(alignment: .leading) {
Text("\(viewModel.ItemName)")
.font(.custom("NunitoSans-Bold", size: 14))
.lineLimit(1)
.multilineTextAlignment(.leading)
Text(viewModel.ItemType == 1 ? "Receta" : "Producto")
.foregroundColor(Color("textColor"))
.font(.custom("NunitoSans-Light", size: 12))
}
Spacer()
}.frame(height: 50)
.padding(EdgeInsets(top: 0, leading: 24, bottom: 0, trailing: 24)).onTapGesture {
self.isCollapsed.toggle()
}
}
if self.viewModel.ItemType == 1 {
if self.isCollapsed {
SpoonListProductView(viewModel: SpoonListProductViewModel(items: self.viewModel.ItemList, father: self.viewModel.ItemId))
}
}
}
}
}
And this is the view that present the childs when is expanded
struct SpoonListProductView: View {
@EnvironmentObject var globalData: GlobalData
@ObservedObject var viewModel: SpoonListProductViewModel
@State private var isInEditingMode: Bool = false
var fatherId: Int?
init(viewModel: SpoonListProductViewModel) {
self.viewModel = viewModel
}
var body: some View {
VStack(alignment: .leading) {
ForEach(viewModel.dataSource) { vm in
Group{
HStack {
SpoonProductView.init(viewModel: vm).onLongPressGesture {
self.isInEditingMode = true
}
Spacer()
if self.isInEditingMode {
Image(systemName: "trash.fill").foregroundColor(Color("textColor")).onTapGesture {
self.delete(vm: vm)
}
}
}
Divider()
}
}
}.padding(EdgeInsets(top: 8, leading: 8, bottom: 0, trailing: 8))
}
func delete(vm: ProductViewModel) {
//self.viewModel.ItemList?.remove(atOffsets: offsets)
self.globalData.deleteProductFromItemList(product: vm.product, itemId: self.viewModel.father!)
}
}
这是列表的代码:
struct SpoonListView: View {
@EnvironmentObject var globalData: GlobalData
@ObservedObject var viewModel: SpoonListViewModel
var items: [Item?]
init(items: [Item?] ) {
self.items = items
self.viewModel = SpoonListViewModel(items: self.items)
}
var body: some View {
SpoonListItemsView(viewModel: viewModel.dataSource!)
}
}
这是它的viewModel:
class SpoonListViewModel: ObservableObject, Identifiable {
@Published var dataSource: SpoonListItemsViewModel? = nil
var items: [Item?]
init(items: [Item?]) {
self.items = items
self.dataSource = SpoonListItemsViewModel(items: self.items as! [Item])
}
}
答案 0 :(得分:0)
这里的问题不是SpoonListItemView
,而是女巫认为的。 @State
应该在渲染之间保留,但是在这种情况下,List
中有ForEach
或SpoonListView
个元素。每次更改后,该列表都会重新呈现。我认为将openIndex
状态移到列表中,或者更高级别可以是一种解决方案。
此外,您可以通过用GlobalData
覆盖综合来掩盖let objectWillChange = ObservableObjectPublisher()
中的事件,但这意味着您必须在其他场合手动调用。所以,我会避免这种情况。
PS:为了更好地理解,您是否还可以添加列表的代码?