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

Posted

技术标签:

【中文标题】如何在 SwiftUI 的父视图中获取子视图的变量值?【英文标题】:How to get variable value of child view in parent view on SwiftUI? 【发布时间】:2021-12-30 05:58:18 【问题描述】:

我有一个视图“CancelRow”,其中 isSelected 的值正在改变

     struct CancelRow: View 
            @Binding var isSelected: Bool
        
            init(isSelected: Binding<Bool>) 
                self._isSelected = isSelected
            
        
           @ViewBuilder var body: some View 
            HStack 
               Text(verbatim: "Hello, \(isSelected)")
            

            CustomCheckbox(checkboxType: .withTrailingLabel, 
             checkboxTitle: "", isActive: $canCancel, isSelected: $isSelected)
        
        .onTapGesture 
                    isSelected.toggle()
                
            

我有另一个视图,我想根据“CancelRow”中的“isSelected”显示按钮是否处于活动状态

// 另一个视图

CancelRow(isSelected: .constant(false))
    Spacer()
    SubmitButtonView(buttonTitle: title, buttonCallBack: 
        goToOtherScreen()
    , isActive: isSelected ) // how to access this variable from  "CancelRow"

【问题讨论】:

状态应该由父视图拥有并传递给子视图——你不应该尝试进入子视图或兄弟视图的状态 @jnpdx 你能帮我写代码吗..我尝试了没有init方法的示例解决方案..但不确定如何使用init方法访问“CancelRow”中的变量 “isSelected”值是 false 或 true.. 仅在 CancelRow 中才知道我如何从父级传递它..plz 建议 在父视图上使用@State并将其传递给子视图,而不是使用.constant,它无论如何都无法更新 请不要将same问题发两次 【参考方案1】:

如 cmets 中所述,状态应由父视图拥有,然后传递给子视图。

在您的情况下,您实际上不需要在您提供的示例中为 CancelRow 使用自定义初始化程序(您可以仅依赖合成初始化程序),但作为请求,这使用初始化器。

struct CancelRow: View 
    @Binding var isSelected: Bool
    
    init(isSelected: Binding<Bool>) 
        self._isSelected = isSelected
    
    
    @ViewBuilder var body: some View 
        HStack 
            Text(verbatim: "Hello, \(isSelected)")
            Button("Toggle") 
                isSelected.toggle()
            
        
    


struct SubmitButtonView : View 
    var buttonTitle : String
    var buttonCallBack : () -> Void
    var isActive : Bool
    
    var body: some View 
        Text("Submit: \(isActive ? "true" : "false")")
    


struct ContentView: View 
    @State private var isSelected = false
    
    var title : String 
        "Title"
    
    
    var body: some View 
        VStack 
            CancelRow(isSelected: $isSelected)
            SubmitButtonView(buttonTitle: title, buttonCallBack: 
                goToOtherScreen()
            , isActive: isSelected )
        
    
    
    func goToOtherScreen() 
        print("Navigate")
    

【讨论】:

感谢您的回答..我遇到的唯一问题是“'Bool'类型的值输入'Binding'”..我刚刚更新了问题..请建议有了这个 我不明白您的新更新中“数据”的来源。相反,只需使用我在答案中提供的代码即可。传入绑定然后不使用它是没有意义的…… 是的。但是在我的情况下,我有复选框..它在“CancelRow”本身中......意味着“isSelected”在“CancelRow”中发生变化 我不太确定这意味着什么。听起来您想将不同的状态传递给 CancelRow 和 SubmitButtonView,这与您的问题所说的基本相反。 我在“CancelRow”中使用的 isSelecteds.toggle() ..抱歉造成混淆【参考方案2】:

Source of truth这个概念。简而言之,您需要在其中一个结构中包含@State private var。如果 @State private var 包含其他结构想要使用的任何信息,则第二个结构应该具有 @Binding var 并从第一个结构初始化为 @State private var

在下面的代码中,struct AnotherView 是事实的来源,它有@State private var,而其他结构有@Binding,并使用@State private var 的值进行初始化。

构造另一个视图:

@State private var isSelected = false

var body: some View 
    VStack 
        CancelRow(isSelected: $isSelected)
        
        Spacer()
        
        SubmitButtonView(isSelected: $isSelected)
    

结构取消行:

@Binding var isSelected: Bool

var body: some View 
    Text(isSelected ? "I'm selected" : "I'm not selected")
 

结构提交按钮视图:

@Binding var isSelected: Bool

var body: some View 
    Button 
        // do something on tap
     label: 
        Text("Button text")
    

【讨论】:

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

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

SwiftUI 在视图之间切换

如何在 swiftui 中为子视图设置私有状态变量?

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

如何使用 SwiftUI 重置子视图状态变量?

SwiftUI - 使用 ForEach 时,您应该在子视图中使用 `@State var` 还是 `let`