SwiftUI Optional TextField

前端 未结 4 2022
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-29 08:17

Can SwiftUI Text Fields work with optional Bindings? Currently this code:

struct SOTestView : View {
    @State var test: String? = \"Test\"

    var body: s         


        
相关标签:
4条回答
  • 2020-11-29 08:42

    You can try

    struct SOTestView : View {
        @State var test: String? = "Test"
    
        var body: some View {
            test.map {
                TextField($0)
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 08:51

    True, at the moment TextField in SwiftUI can only be bound to String variables, not String?. But you can always define your own Binding like so:

    import SwiftUI
    
    struct SOTest: View {
        @State var text: String?
    
        var textBinding: Binding<String> {
            Binding<String>(
                get: {
                    return self.text ?? ""
            },
                set: { newString in
                    self.text = newString
            })
        }
    
        var body: some View {
            TextField("Enter a string", text: textBinding)
        }
    }
    

    Basically, you bind the TextField text value to this new Binding<String> binding, and the binding redirects it to your String? @State variable.

    0 讨论(0)
  • 2020-11-29 08:55

    Ultimately the API doesn't allow this - but there is a very simple and versatile workaround:

    extension Optional where Wrapped == String {
        var _bound: String? {
            get {
                return self
            }
            set {
                self = newValue
            }
        }
        public var bound: String {
            get {
                return _bound ?? ""
            }
            set {
                _bound = newValue.isEmpty ? nil : newValue
            }
        }
    }
    

    This allows you to keep the optional while making it compatible with Bindings:

    TextField($test.bound)
    
    0 讨论(0)
  • 2020-11-29 08:55

    You can add this operator overload, then it works as naturally as if it wasn't a Binding.

    func ??<T>(lhs: Binding<Optional<T>>, rhs: T) -> Binding<T> {
        Binding(
            get: { lhs.wrappedValue ?? rhs },
            set: { lhs.wrappedValue = $0 }
        )
    }
    

    This creates a Binding that returns the left side of the operator's value if it's not nil, otherwise it returns the default value from the right side.

    When setting it only sets lhs value, and ignores anything to do with the right hand side.

    It can be used like this:

    TextField("", text: $test ?? "default value")
    
    0 讨论(0)
提交回复
热议问题