SwiftUI List использует фильтр, сталкивается с проблемами обновления состояния - PullRequest
1 голос
/ 08 марта 2020

Немного сложно объяснить, в чем проблема. Возможно, проще всего запустить код и отредактировать одну из моделей, а затем посмотреть, что происходит с подробным представлением. Но я попытаюсь объяснить:)

У меня есть представление, в котором я показываю список компьютеров, разбитых на два раздела на основе поля в модели Computer. Вы можете нажать на компьютер, чтобы показать его подробный экран, на котором есть кнопка для редактирования компьютера.

Проблема возникает при редактировании логического значения isLaptop. Допустим, вы открываете iMa c, меняете isLaptop на true и сохраняете форму. На подробном экране все еще написано «Это не ноутбук», хотя теперь он должен сказать «Это ноутбук». Когда вы вернетесь к представлению списка, вы увидите, что список обновлен правильно и iMa c перемещен в раздел «Ноутбуки».

Я предполагаю, что как только я отредактирую поле isLaptop, что DetailView в основном становится сиротой, поскольку ContentView воссоздает свое тело, список изменился из-за фильтра, и теперь DetailView больше не "связан" с тем, что уже на экране. Я думал, что добавление .id(computer.id) к NavigationLink поможет, но, к сожалению, это не так.

Итак, как можно сделать так, как ожидается, чтобы отфильтрованный список с двумя его разделами работал, но когда вы изменить поле, которое фильтруется, подпредставления также восстанавливаются правильно, как и ожидалось?

import SwiftUI

struct Computer: Identifiable {
  var id: Int
  var name: String
  var isLaptop: Bool
}

class Store: ObservableObject {
  @Published var computers: [Computer] = [
    Computer(id: 0, name: "Macbook", isLaptop: true),
    Computer(id: 1, name: "iMac", isLaptop: false),
  ]
}

struct ContentView: View {
  @EnvironmentObject private var store: Store

  var body: some View {
    NavigationView {
      List {
        Section(header: Text("Laptops")) {
          ForEach(store.computers.filter { $0.isLaptop == true }) { computer in
            NavigationLink(destination: DetailView(computer: computer)) {
              Text(computer.name)
            }
          }
        }

        Section(header: Text("Other computers")) {
          ForEach(store.computers.filter { $0.isLaptop == false }) { computer in
            NavigationLink(destination: DetailView(computer: computer)) {
              Text(computer.name)
            }
          }
        }
      }
      .listStyle(GroupedListStyle())
      .navigationBarTitle("Computers")
    }
  }
}

struct DetailView: View {
  let computer: Computer

  @EnvironmentObject private var store: Store
  @State private var editing = false

  var body: some View {
    VStack {
      Text(computer.name)
      Text(computer.isLaptop ? "This is a laptop" : "This is not a laptop")
    }
    .navigationBarItems(trailing: Button("Edit") {
      self.editing = true
    })
    .sheet(isPresented: $editing) {
      FormView(computer: self.computer)
        .environmentObject(self.store)
    }
  }
}

struct FormView: View {
  @EnvironmentObject private var store: Store
  @Environment(\.presentationMode) private var presentationMode
  @State private var computer: Computer

  init(computer: Computer) {
    _computer = State(initialValue: computer)
  }

  var body: some View {
    NavigationView {
      Form {
        TextField("Name", text: $computer.name)
        Toggle("Is Laptop", isOn: $computer.isLaptop)
      }
      .navigationBarTitle("Edit Computer")
      .navigationBarItems(trailing: Button("Save") {
        self.store.computers = self.store.computers.filter { $0.id != self.computer.id } + [self.computer]
        self.presentationMode.wrappedValue.dismiss()
      })
    }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

1 Ответ

0 голосов
/ 08 марта 2020

Хорошо, мне удалось найти обходной путь:

struct ContentView: View {
  @EnvironmentObject private var store: Store

  @State private var selected: Int?

  var body: some View {
    NavigationView {
      VStack {
        List {
          Section(header: Text("Laptops")) {
            ForEach(store.computers.filter { $0.isLaptop == true }) { computer in
              Button(computer.name) {
                self.selected = computer.id
              }
            }
          }

          Section(header: Text("Other computers")) {
            ForEach(store.computers.filter { $0.isLaptop == false }) { computer in
              Button(computer.name) {
                self.selected = computer.id
              }
            }
          }
        }

        ForEach(store.computers) { computer in
          NavigationLink(destination: DetailView(computer: computer), tag: computer.id, selection: self.$selected) {
            EmptyView()
          }
        }
      }
      .listStyle(GroupedListStyle())
      .navigationBarTitle("Computers")
    }
  }
}

К сожалению, эти виды ссылок NavigationLink ведут себя довольно плохо на симуляторе, но на устройстве это хорошо, и лучшее, что я придумаю ?‍♂️

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...