【问题标题】:Pass an @State variable to ContentView将@State 变量传递给 ContentView
【发布时间】:2021-02-26 07:14:18
【问题描述】:

构建我的第一个 SwiftUI 应用程序,但我一直坚持将 @State var 传递给 ContentView。我在一个结构中声明了@State 变量,在 ContentView 中的变量上有一个@Binding 标记。

我的意图是在 ContentView 中调用 NumberBlock 的多个实例,并且能够通过一个按钮将它们全部重置为 false(隐藏所有图像)。

Xcode 12 中添加的新“App”结构会因缺少参数而出错。我已经尝试了所有我能想到的输入参数,但似乎没有任何效果。我可以通过使用 .constant(true) 来消除错误,但这并没有提供我需要的功能,即从 ContentView 切换变量。

感谢任何帮助消除错误或纠正我对@State 和@Binding 的浅薄理解。

这里是我创建@State reset_x var的地方

import SwiftUI

struct NumberBlock: View {
    
    @State var reset_x: Bool = true
    
    @Binding var reset: Bool
    
    var body: some View {
        ZStack {
            
            Text("test")
                .onTapGesture(count: 1, perform: {
                    self.reset_x = false
                })
            Image("XMark")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 50, height: 50, alignment: .center)
                .onTapGesture(count: 1, perform: {
                    self.reset_x = true
                    print("reset_x is \(self.reset_x)")
                })
                
                .isHidden(reset_x ? true : false)
                .isHidden(reset ? true : false)
        
        }
    }
}

此视图出现错误:

import SwiftUI

@main
struct Quixx2App: App {
        
    var body: some Scene {
        
        WindowGroup {
            ContentView()
        }
    }
}

这里是我想使用@Binding的地方

import SwiftUI

struct ContentView: View {
    
    @State var reset: Bool = false
    @Binding var reset_x: Bool
    
    var body: some View {
        VStack {
            HStack {
                NumberBlock(reset: self.$reset)
                NumberBlock(reset: self.$reset)
            }
            Button("Reset Score"){
                self.scoreKeeper.redScore = 0
                self.reset_x = false //this line is not doing anything
                print("reset_x is \(self.reset_x)")
            }

        }
    }
}

还有 .isHidden 扩展名

import Foundation
import SwiftUI

extension View {   
    @ViewBuilder func isHidden(_ hidden: Bool, remove: Bool = false) -> some View {
        if hidden {
            if !remove {
                self.hidden()
            }
        } else {
            self
        }
    }
}

【问题讨论】:

  • 我说对了吗?如果单击文本视图,则应显示其自己的 NumberBlock 中的图像。如果您单击该图像,它应该再次被隐藏。如果你点击“重置分数”,所有 Numberblocks 中的所有图像都应该被隐藏。
  • 是的,完全正确

标签: binding swiftui state


【解决方案1】:

让我们从您的NumberBlock 视图开始。您需要视图中的一种状态,该状态会保留图像是否隐藏。通过点击文本视图,切换值并相应地呈现视图。

struct NumberBlock: View {
    @State private var imageIsHidden: Bool
    
    var body: some View {
        VStack {
            Text("Show")
                .onTapGesture(count: 1, perform: {
                    self.imageIsHidden = false
                })
            
            Text("Image")
                .onTapGesture(count: 1, perform: {
                    self.imageIsHidden = true
                })
                .isHidden(imageIsHidden ? true : false)
        }
    }
}

现在,您需要第二个功能:ContentView 应该控制此状态。所以你必须把这个状态从子视图(NumberBlock)提取到父视图(ContentView)。通过将属性从 @State 更改为 @Binding,您基本上是在告诉子视图此数据是从父视图传递的。

我的工作示例:

import SwiftUI
import Foundation

extension View {
    @ViewBuilder func isHidden(_ hidden: Bool, remove: Bool = false) -> some View {
        if hidden {
            if !remove {
                self.hidden()
            }
        } else {
            self
        }
    }
}

struct NumberBlock: View {
    @Binding var imageIsHidden: Bool
    
    var body: some View {
        VStack {
            Text("Show")
                .onTapGesture(count: 1, perform: {
                    self.imageIsHidden = false
                })
            
            Text("Image")
                .onTapGesture(count: 1, perform: {
                    self.imageIsHidden = true
                })
                .isHidden(imageIsHidden ? true : false)
        }
    }
}

struct ContentView: View {
    @State var imageOfBlock1IsHidden: Bool = true
    @State var imageOfBlock2IsHidden: Bool = true
    
    var body: some View {
        VStack {
            HStack {
                NumberBlock(imageIsHidden: self.$imageOfBlock1IsHidden)
                NumberBlock(imageIsHidden: self.$imageOfBlock2IsHidden)
            }
            
            Button("Reset Score") {
                self.imageOfBlock1IsHidden = true
                self.imageOfBlock2IsHidden = true
            }
        }
    }
}

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

【讨论】:

  • 谢谢,这很有帮助。所以在这种情况下,我会为每个图像创建一个@State var?我认为这会起作用,但总共会有大约 50 张图像,这意味着要管理的变量列表很长。
  • 是的,正确的。如果您的逻辑变得复杂,请考虑引入 ViewModel 是否有意义。但这就像在没有额外信息的情况下在黑暗中刺伤。
猜你喜欢
  • 2023-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-24
  • 2012-02-13
  • 2014-09-05
  • 2011-10-13
相关资源
最近更新 更多