Home > Enterprise >  How to get variable value of child view in parent view on SwiftUI?
How to get variable value of child view in parent view on SwiftUI?

Time:12-31

I have one view "CancelRow"

struct CancelRow: View {
    @Binding var isSelected: Bool

    init(isSelected: Binding<Bool>) {
        self._isSelected = isSelected //just to get bool value
    }

   @ViewBuilder var body: some View {
    HStack {
       Text(verbatim: "Hello, \(isSelected)")
    }
}

I have another view i which i want to show button active or not based on "isSelected" from "CancelRow"

// AnotherVIew

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

CodePudding user response:

As mentioned in the comments, state should be owned by a parent view and then passed to the child views.

In your case, you don't actually need to use a custom initializer for CancelRow in the example you gave (you could rely on just the synthesized initializer), but as request, this uses an initializer.

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

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 {
            Button("Toggle") {
                isSelected.toggle()
            }
            CancelRow(isSelected: $isSelected)
            SubmitButtonView(buttonTitle: title, buttonCallBack: {
                goToOtherScreen()
            }, isActive: isSelected )
        }
    }
    
    func goToOtherScreen() {
        print("Navigate")
    }
}

CodePudding user response:

There is this concept of Source of truth. In oversimplified terms, you need to have a @State private var in one of your structs. If that @State private var holds any information some other struct would like to use, the second struct should have @Binding var and be initialised from the first struct with the value of @State private var.

In code below struct AnotherView is the source of truth, it has @State private var, and other structs have @Binding and are initialised with value of that @State private var.

struct AnotherView:

@State private var isSelected = false

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

struct CancelRow:

@Binding var isSelected: Bool

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

struct SubmitButtonView:

@Binding var isSelected: Bool

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