根据本文,创建具有不同类型的自定义Binding用于绑定和显示应该很简单。这是我不工作的例子:
import SwiftUI
struct BindingButton: View {
@Binding var title: String
var onTap: () -> Void
var body: some View {
Button {
onTap()
} label: {
Text(title)
}
}
}
struct CustomBinding: View {
@State var date: Date
@State var int: Int
lazy var descriptiveDate = Binding(
get: { //Escaping closure captures mutating 'self' parameter
return self.date.description
},
set: { _ in }
)
lazy var descriptiveInt = Binding(
get: { //Escaping closure captures mutating 'self' parameter
return String(self.int)
},
set: { _ in }
)
var body: some View {
VStack {
// Cannot find '$descriptiveDate' in scope
BindingButton(title: $descriptiveDate) {
date = Date()
}
// Cannot find '$descriptiveInt' in scope
BindingButton(title: $descriptiveInt) {
int += 2
}
}
}
}
我想绑定日期和Int,但使用字符串显示。有没有可能没有双重绑定?我的意思是我想避免为日期和Int创建第一个绑定,然后.onChange
更新字符串和字符串的另一个绑定。我必须这样做吗,或者有更优雅的方法?
Binding
根据定义是双向连接。lazy
表示代码只运行一次。基于此和空的set
,您的descriptiveDate
和descriptiveInt
不需要是Binding
,只是String
的get
struct CustomBinding: View {
@State var date: Date
@State var int: Int
var descriptiveDate: String {
date.description
}
var descriptiveInt : String{
String(self.int)
}
var body: some View {
VStack {
BindingButton(title: descriptiveDate) {
date = Date()
}
BindingButton(title: descriptiveInt) {
int += 2
}
}
}
}
struct BindingButton: View {
let title: String
var onTap: () -> Void
var body: some View {
Button {
onTap()
} label: {
Text(title)
}
}
}
lazy
不与SwiftUI
View
工作,当@State
触发重画时,您需要重新计算body
和描述性变量。
我完全同意前面的答案,在这种情况下不需要绑定。但是为了解决问题的另一部分:"有没有可能在没有双重绑定的情况下拥有相互依赖的@State
和@Binding
?">
首先,即使在最原始的方式中,您也不需要自定义绑定。相反,你可以使用两个状态变量:
@State var descriptiveDate: String
@State var descriptiveInt: String
并利用didSet
:
@State var date: Date {
didSet {
descriptiveDate = date.description
}
}
@State var int: Int {
didSet {
descriptiveInt = String(int)
}
}
@State var descriptiveDate: String
@State var descriptiveInt: String
或者为date
和int
状态实现onChange
:
struct CustomBinding: View {
@State var date: Date
@State var int: Int
@State var descriptiveDate: String
@State var descriptiveInt: String
var body: some View {
VStack {
BindingButton(title: $descriptiveDate) {
date = Date()
}
.onChange(of: date) { newDate in
descriptiveDate = newDate.description
}
BindingButton(title: $descriptiveInt) {
int += 2
}
.onChange(of: int) { newInt in
descriptiveInt = String(int)
}
}
}
}
但是这仍然有点多余,因为您将为每个变量复制@State
。因此,为了避免自定义绑定是有帮助的:
BindingButton(title: Binding(
get: { int.description },
set: { int = Int($0)! }
)) {
int += 2
}
也就是说:你不需要为每个状态保留额外的状态,同时仍然有可能从子改变父值。在这个具体的例子中没有多大意义,但在某些情况下是有意义的。
我们是否避免了"double"变量——不完全是。因为你有两条信息,它们可以按照一定的规则变化,但它们是独立的,所以你确实需要两个东西。但是自定义绑定只是一种可能性。