如何在 SwiftUI 中重置子视图?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中重置子视图?【英文标题】:How to reset a subview in SwiftUI? 【发布时间】:2020-08-01 20:47:39 【问题描述】:

下面是我正在使用的代码的简化版本。但是每当我 resetKeyboard() 它仍然显示以前的键盘。无论如何,当我调用 resetKeyboard() 时,它会用新的 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()
    

【问题讨论】:

你没有调用 resetKeyboard()。 @MohammadRahchamani 抱歉,我忘了把它添加到帖子中,我刚刚修复了它。但这是在我的实际项目中调用的,但我仍然遇到错误。 KeyboardView 是什么,.change() 有什么作用? @NewDev KeyboardView 是一堆自定义按钮,当您按下切换按钮时。例如 .change() 可以切换一个随机按钮。不过应该没太大关系吧?因为我遇到的问题只是试图用一个新的keyboardView替换一个。 @JackBodine,其中一些确实很重要,因为我不明白“替换视图”是什么意思。你说得对,具体的实现并不重要,但我认为你需要解释你到底想对KeyboardViewGameView 发生什么。 【参考方案1】:

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

所以,SwiftUI 得到的是myKeyboard 的初始副本(请记住,它是值类型struct),而不是您要更改的副本。

在正常使用情况下,您不会将各种 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 的实例并将其传递给子级:

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)")
   


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

父母可以通过不同的方式向孩子“传达信息”。

但总体而言,Views 应该被认为是声明性结构——而不是活生生的实例——而数据是驱动这些视图变化的驱动力。你需要决定谁最能掌握真相的来源。

【讨论】:

以上是关于如何在 SwiftUI 中重置子视图?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 子视图中执行函数?

如何在 SwiftUI 中从减去的子视图中关闭视图

如何在最新的 SwiftUI App 中获取窗口或视图的所有子视图?

如何在 SwiftUI 的父视图中获取子视图的变量值?

如何在 SwiftUI 中禁用子视图上的特定状态更改动画

SwiftUI 动画如何与子视图隔离?