Как сбросить подвид в SwiftUI? - PullRequest
0 голосов
/ 01 августа 2020

Ниже представлена ​​упрощенная версия кода, который я использую. Но всякий раз, когда я resetKeyboard (), он все еще показывает предыдущую клавиатуру. Есть ли способ сделать это так, когда я вызываю resetKeyboard (), он заменяет клавиатуру на fre sh KeyboardView?

struct GameView: View {
    @State var myKeyboard = KeyboardView()

    var body: some View {
        VStack{
            Button("Change Keyboard") {
                myKeyboard.change()
            }


            myKeyboard

            Button("Reset Keyboard") {
                resetKeyboard()
            }
        }
    }

    func resetKeyboard(){
        self.myKeyboard = KeyboardView()
    }
}

1 Ответ

0 голосов
/ 02 августа 2020

SwiftUI создает дерево представления из View объектов в body их родителей.

Итак, SwiftUI получил начальную копию (помните , это тип значения struct) из myKeyboard, а не копия, которую вы изменяете.

При нормальном использовании вы не сохраняете экземпляры различных View в виде переменных (я имею в виду, вы можете , но вам нужно глубоко понять, что происходит).

Что вы, вероятно, захотите, так это изменить данные, которые управляют дочерним представлением. Где (должны) храниться эти данные? Это зависит от того, что вы хотите сделать.

В большинстве случаев родитель «владеет» состоянием, т.е. имеет источник истинности некоторых данных, на которые опирается ребенок. Затем легко изменить состояние и передать состояние дочернему элементу через его init:

struct ChildView: View {
   let number: Int

   var body: some View {
      Text("\(number)")
   }
}

struct ParentView: View {
   @State var random: Int = Int.random(1...100)

   var body: some View {
      VStack() {
         ChildView(number: random)
         Button("randomize") { 
            self.random = Int.random(1...100)
         }
      }
   }
}

Но, скажем, родитель не хочет выполнять рандомизацию, т.е. дочерний элемент должен иметь дело с этим.

Правильный подход - создать модель представления для дочернего элемента, которую родитель (или собственная модель представления родителя) может владеть и передавать через init, и тогда модель представления будет иметь дело с нюансами рандомизации.

class ChildVM: ObservableObject {
   @Published var random = Int.random(1...100)

   func change() {
      random = Int.random(1...100)
   }
}

Родитель создает экземпляр ChildVM и передает его в child:

struct ParentVuew: View {
   let childVM = ChildVM()

   var body: some View {
      VStack() {
         ChildView(vm: childVm)
         Button("randomize") { 
            self.childVM.change()
         }
      }
   }
}

А дочернее представление просто управляется моделью представления:

struct ChildView: View {
   @ObservedObject let vm: ChildVM

   var body: some View {
      Text("\(vm.random)")
   }
}

Очевидно, это упрощенный пример, которого можно было бы достичь любым количеством способов.

И есть разные способы для родителя «послать сообщение» ребенку.

Но Общий вывод должен заключаться в том, что View следует рассматривать как декларативные структуры, а не как живые экземпляры, а данные - это то, что движет изменениями в этих представлениях. Вам нужно решить, кто лучше владеет источником истины.

...