Обновление среды делает вид перерисовывается со всеми его состояниями Swiftui - PullRequest
1 голос
/ 04 февраля 2020

У меня есть @Environment, в котором хранятся все данные общего доступа для моих просмотров. Одно из моих представлений использует одну из своих переменных, чтобы представить список со сворачиваемыми элементами. Чтобы сделать список свертываемым, я использую @State, имеет ли значение true или false, чтобы развернуть свертываемое содержимое, внутри этого списка я хочу, чтобы пользователь мог удалить его элементы, поэтому я создал функцию, которая удаляет элемент из переменной в @Environment и обновляет представление , Проблема состоит в том, что State меняет свое значение по умолчанию, и расширенный список может быть свернут. Я хотел бы знать, как сохранить прежние состояния или, может быть, сказать, что мои взгляды изменяют только те части, которые действительно меняются.

Это мой объект окружающей среды. Все мои представления имеют доступ к этому.

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])
    }
}

1 Ответ

0 голосов
/ 05 февраля 2020

Проблема здесь не в SpoonListItemView, а в представлении, которое ее держит. @State должно сохраняться между рендерами, но в этом случае у вас есть List или ForEach элементов в вашем (давайте предположим) SpoonListView. который повторно отображает список при каждом изменении. Я думаю, что одним из решений может быть перемещение состояния openIndex в список или более высокий уровень.

Кроме того, вы можете замаскировать событие в GlobalData, переопределив синтезированный с помощью let objectWillChange = ObservableObjectPublisher(), но это будет означать Вы должны позвонить в других случаях вручную. Так что я бы этого избегал.

PS: Для лучшего понимания вы могли бы также добавить код списка?

...