Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Can I use Binding get set custom binding with @Binding property wrapper?

How can I use Binding(get: { }, set: { }) custom binding with @Binding property on SwiftUI view. I have used this custom binding successfully with @State variable but doesn't know how to apply it to @Binding in subview initializer. I need it to observe changes assigned to @Binding property by parent class in order to execute code with some side effects!

like image 455
Michał Ziobro Avatar asked Dec 12 '19 19:12

Michał Ziobro


People also ask

What annotation do we use on a property to set up a binding for SwiftUI?

In SwiftUI, you can create bindings in 2 ways: With the @Binding property wrapper, which creates a binding, but doesn't store it. With other property wrappers, like @State, which creates a binding, and also stores its value.

How do I make my own bindings?

Create a new custom binding by creating an instance of the CustomBinding class and passing the collection outputBec to the constructor. The resulting custom binding shares many of the same characteristics as the standard WSHttpBinding.

What is state and binding in SwiftUI?

@State property wrappers are used to read and write variables from a structure. It is used in single view and is recommended that you set its property as private so that other views cannot access it. @Binding property wrappers are used to access variables from other views.

What is binding string Swift?

String in swift is a value type, so your textValue property is taking a copy of the value, and SwiftUI is monitoring that copy, not the actual value in Controller.message . What you want here is a binding or an observed object—exactly which depends on whether Controller is a struct or a class type.


1 Answers

Here is possible approach. The demo shows two-directional channel through adapter binding between main & dependent views. Due to many possible callback on update there might be needed to introduce redundancy filtering, but that depends of what is really required and out of scope.

Demo code:

struct TestBindingIntercept: View {

    @State var text = "Demo"
    var body: some View {
        VStack {
            Text("Current: \(text)")
            TextField("", text: $text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            Divider()
            DependentView(value: $text)
        }
    }
}

struct DependentView: View {
    @Binding var value: String

    private var adapterValue: Binding<String> {
        Binding<String>(get: {
            self.willUpdate()
            return self.value
        }, set: {
            self.value = $0
            self.didModify()
        })
    }

    var body: some View {
        VStack {
            Text("In Next: \(adapterValue.wrappedValue)")
            TextField("", text: adapterValue)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
    }

    private func willUpdate() {
        print(">> run before UI update")
    }

    private func didModify() {
        print(">> run after local modify")
    }
}
like image 88
Asperi Avatar answered Nov 14 '22 17:11

Asperi