将@State 变量传递给 ContentView

Posted

技术标签:

【中文标题】将@State 变量传递给 ContentView【英文标题】:Pass an @State variable to 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 中的所有图像都应该被隐藏。 是的,完全正确 【参考方案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 是否有意义。但这就像在没有额外信息的情况下在黑暗中刺伤。

以上是关于将@State 变量传递给 ContentView的主要内容,如果未能解决你的问题,请参考以下文章

将命令传递给ContentView中的按钮

如何将javascript变量传递给django模板标签

如何在 Swiftui 中根据彼此初始化 @State 变量?

使用 @State 变量不适用于从子视图更改 Body 中的视图状态

将道具传递给路由器内部的组件

如何在swift中使用其他属性将实例作为属性传递