在SwiftUI中镜像已发布的绑定值



如何将View的Binding值连接到ObservableObject的Published值?

目标:objValue的所有更改都将反映在viewValue上,反之亦然。

注意:不要建议直接使用onChange(obj.objValue({viewValue=$0}修饰符。它将触发View的额外绘制周期(第一个用于objValue,第二个用于viewValue(。

class MyObject: ObservableObject {
@Published var objValue: Int = 0
}
struct MyView: View {
@Binding var viewValue: Int
@StateObject var obj = MyObject()

var body: some View {
Text("Placeholder")
.onChange(viewValue) {
//Do something
}
}
}

这是一个有效的解决方案(还没有直接与Combine一起使用(,它利用View适配器来避免对MyView主体进行额外的重绘。通过将Binding值传递给ValueReaderView,只有它的主体会被触发重新绘制,然后它只是将新结果传递到外部,我们可以使用它。在这里,我们将viewValue的更新值分配给objValue。

这种技术避免了额外的重绘周期,无论objValue或viewValue是先更改的,MyView主体都将只重绘一次。因为viewValue没有直接在正文中使用,所以只有ValueReader会在viewValue更改时跳过MyView的正文重绘而直接重绘。

class MyObject: ObservableObject {
@Published var objValue: Int = 0
}
struct MyView: View {
@Binding var viewValue: Int
@StateObject var obj = MyObject()

var body: some View {
ZStack {
ValueReader(value: $viewValue) { newValue in
obj.objValue = newValue //Mirroring viewValue to obj.objValue
}

Text("Placeholder")
.onChange(of: obj.objValue, perform: handleValue)
}
}

private func handleValue(_ value: Int) {
viewValue = value //Mirroring obj.objValue to viewValue
//Do any job here. For example just send analytics
}

private struct ValueReader: View {
@Binding var value: Int
let onChange: (_ newValue: Int) -> ()

var body: some View {
Color.clear
.onChange(of: value) { newValue in
onChange(newValue)
}
}
}
}

最新更新