SwiftUI可选TextField

时间:2019-07-13 18:17:20

标签: swiftui

SwiftUI文本字段可以与可选绑定一起使用吗?当前此代码:

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

    var body: some View {
        TextField($test)
    }
}

产生以下错误:

  

无法将类型'Binding '的值转换为预期的参数类型'Binding '

有什么办法解决吗?在数据模型中使用Optionals是一种非常常见的模式-实际上,这是Core Data中的默认设置,因此SwiftUI不支持它们似乎很奇怪

6 个答案:

答案 0 :(得分:25)

您可以添加此运算符重载,然后它像不是绑定一样自然工作。

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

这将创建一个Binding,如果它不为nil,则返回操作符值的左侧,否则它将从右侧返回默认值。

设置时仅设置lhs值,而忽略与右侧有关的任何事情。

可以这样使用:

TextField("", text: $test ?? "default value")

答案 1 :(得分:5)

是的,目前SwiftUI中的TextField只能绑定到String变量,不能绑定到String?。 但是您总是可以这样定义自己的Binding

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)
    }
}

基本上,您将TextField文本值绑定到此新的Binding<String>绑定,绑定将其重定向到您的String? @State变量。

答案 2 :(得分:1)

您可以尝试

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

    var body: some View {
        test.map {
            TextField($0)
        }
    }
}

答案 3 :(得分:0)

对于结束,正如@kontiki在注释中指出的那样,这是不可能的,因为TextField需要Binding 而不是Binding 。要创建如上所述的可选TextField,需要将Binding 转换为Binding

有关如何执行此操作的问题,请参见以下问题:How to Use BindingConvertible in SwiftUI?

答案 4 :(得分:0)

尝试一下:

struct ContentView : View {

@Binding var test: String

var body: some View {
    TextField("Test",text: self.$test)
}
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
    ContentView(test: .constant(""))

    }
}
#endif

答案 5 :(得分:0)

一个可能的解决方案是创建一个自定义扩展:

extension Binding {
    func unwrapped<Wrapped>(
        defaultValue: Wrapped
    ) -> Binding<Wrapped> where Value == Wrapped? {
        .init(
            get: { wrappedValue ?? defaultValue },
            set: { wrappedValue = $0 }
        )
    }
}

并像这样使用它:

TextField("", text: $test.unwrapped(defaultValue: "text"))