SwiftUI文本字段可以与可选绑定一起使用吗?当前此代码:
struct SOTestView : View {
@State var test: String? = "Test"
var body: some View {
TextField($test)
}
}
Run Code Online (Sandbox Code Playgroud)
产生以下错误:
无法将类型'Binding <String?>'的值转换为预期的参数类型'Binding <String>'
有没有办法解决?在数据模型中使用Optionals是一种非常常见的模式-实际上,这是Core Data中的默认设置,因此SwiftUI不支持它们似乎很奇怪
Jon*_*an. 50
您可以添加此运算符重载,然后它就像不是 Binding 一样自然地工作。
func ??<T>(lhs: Binding<Optional<T>>, rhs: T) -> Binding<T> {
Binding(
get: { lhs.wrappedValue ?? rhs },
set: { lhs.wrappedValue = $0 }
)
}
Run Code Online (Sandbox Code Playgroud)
这将创建一个 Binding,如果它不是 nil,则返回运算符值的左侧,否则从右侧返回默认值。
设置时只设置 lhs 值,而忽略与右侧有关的任何事情。
它可以像这样使用:
TextField("", text: $test ?? "default value")
Run Code Online (Sandbox Code Playgroud)
确实,目前TextField
在 SwiftUI 中只能绑定到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)
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,您将TextField
文本值绑定到这个新Binding<String>
绑定,然后绑定将它重定向到您的String?
@State 变量。
最终,API不允许这样做-但是有一个非常简单且通用的解决方法:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
这使您可以保留可选内容,同时使其与Bindings兼容:
TextField($test.bound)
Run Code Online (Sandbox Code Playgroud)
我更喜欢@Jonathon提供的答案。Optional
因为它简单而优雅,并且为编码器提供了当is .none
(= nil
) 和 not 时的原位基本情况.some
。
不过,我觉得值得在这里添加我的两分钱。我通过阅读 Jim Dovey 关于SwiftUI Bindings with Core Data的博客学到了这项技术。其本质上与@Jonathon 提供的答案相同。但确实包含一个很好的模式,可以针对多种不同的数据类型进行复制。
首先创建一个扩展Binding
public extension Binding where Value: Equatable {
init(_ source: Binding<Value?>, replacingNilWith nilProxy: Value) {
self.init(
get: { source.wrappedValue ?? nilProxy },
set: { newValue in
if newValue == nilProxy { source.wrappedValue = nil }
else { source.wrappedValue = newValue }
}
)
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的代码中使用这样的......
TextField("", text: Binding($test, replacingNilWith: String()))
Run Code Online (Sandbox Code Playgroud)
或者
TextField("", text: Binding($test, replacingNilWith: ""))
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1036 次 |
最近记录: |