如何在 SwiftUI 中重置子视图? [英] How to reset a subview in SwiftUI?

查看:28
本文介绍了如何在 SwiftUI 中重置子视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是我正在使用的代码的简化版本.但是每当我 resetKeyboard() 它仍然显示以前的键盘.无论如何,当我调用 resetKeyboard() 时,它会用新的 KeyboardView 替换键盘吗?

Below is a simplified version of the code that I'm using. But whenever I resetKeyboard() it still shows the previous keyboard. Is there anyway to make it so when I call resetKeyboard() it replaces the keyboard with a fresh 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()
    }
}

推荐答案

SwiftUI 从其父对象的 body 中的 View 对象构造一个视图树.

SwiftUI constructs a view tree from View objects in body of their parents.

所以,SwiftUI 得到的是 myKeyboard 的初始copy(记住,它是一个值类型的struct)代码>,而不是您要更改的副本.

So, what SwiftUI got was the initial copy (remember, it's a value-type struct) of myKeyboard, not the copy you are changing.

在正常使用情况下,您不会将各种 View 的实例存储为变量(我的意思是,您可以,但您需要深入了解发生了什么).

Under normal usage, you don't keep instances of various View stored as variables (I mean, you can, but you'd need to understand in depth what's going on).

您可能想要的是更改驱动子视图的数据.这些数据(应该)在哪里?这取决于你想做什么.

What you probably want is to change the data that drives the child view. Where does (should) this data live? It depends on what you want to do.

在大多数情况下,父母拥有"国家,即拥有儿童所依赖的某些数据的真实来源.然后改变状态并通过它的 init 将状态传递给孩子就很简单了:

In most cases the parent "owns" the state, i.e. has the source of truth of some data that the child relies on. Then it's trivial to change the state and pass the state to the child via its 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)
         }
      }
   }
}


但是,比如说,父母不想进行随机化 - 即孩子应该处理它.


But, say, the parent doesn't want to do the randomization - i.e. the child should deal with it.

正确的做法是为子级创建一个视图模型,父级(或父级自己的视图模型)可以拥有并通过init传递,然后视图模型会处理细微差别随机化.

The proper approach is to create a view model for the child, which the parent (or the parent's own view model) could own and pass via init, and then the view model would deal with nuances of randomization.

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

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

父级创建一个 ChildVM 实例并将其传递给子级:

The parent creates an instance of ChildVM and passes it to the child:

struct ParentVuew: View {
   let childVM = ChildVM()

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

而子视图只是由视图模型驱动:

And the child view is simply driven by the view model:

struct ChildView: View {
   @ObservedObject let vm: ChildVM

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


显然,这是一个可以通过多种方式实现的简化示例.


Obviously, this is a simplified example that could have been achieved in any number of ways.

父母可以通过不同的方式发送消息"孩子.

And there are different ways for the parent to "message" the child.

但一般的结论应该是 View 应该被视为声明性结构 - 而不是活的实例 - 而数据是驱动这些视图发生变化的动力.您需要决定谁最能拥有真相的来源.

But the general takeaway should be that Views should be thought of as declarative structures - not living instances - and the data is what drives the changes in those views. You need to decide who is best to own the source of truth.

这篇关于如何在 SwiftUI 中重置子视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆