按照 SwiftUI 的设计准则,View 绑定的数据源变化会触发 View 改写。但是在某些情况下咱们需求在数据源没变化的时分自动改写 View。体系没有给 View 供给一个一致的 refresh
或者 reload
办法。于是咱们只能用一些非主流的办法来完成。本文介绍两种办法完成手动触发 View 改写。
自定义ObservedObject
SwiftUI 状况办理 @ObservedObject
的生命周期和 View 保持一致。当 View 被从头求值时,相关的ObservedObject
也会被从头初始化。同理 ObservedObject
变化时也会触发 View 从头求值。因而咱们能够自定义一个 ObservedObject 实例,通过触发 ObservedObject 状况变化促进 View 改写。
代码完成
定义一个 ObservableObject:
class TriggerViewModel: ObservableObject {
func updateView() {
self.objectWillChange.send()
}
}
在 View 中声明成 @ObservedObject 特点:
struct ContentView: View {
@ObservedObject var refreshTrigger = TriggerViewModel()
var body: some View {
VStack {
RandomView()
.frame(width: 150, height: 150)
Button("改写") {
updateViewModel()
}
.font(.headline)
.buttonStyle(.borderedProminent)
}
}
private func updateViewModel() {
refreshTrigger.updateView()
}
}
有了 refreshTrigger 后,咱们调用内部的 updateView
办法就能够让 View 改写。
Tips:由于每次 View 更新都会对 @ObservedObject 从头求值,但是通常情况下 View 的更新并不需求相关的特点从头初始化。因而 SwiftUI 后边推出了 @StateObject。
Demo 说明:RandomView 每次改写就会变换背景色。
struct RandomView: View {
let randomH = Double.random(in: 0...1.0)
let randomS = Double.random(in: 0...1.0)
let randomL = Double.random(in: 0...1.0)
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 12)
.foregroundColor(Color(hue: randomH, saturation: randomS, brightness: randomL))
VStack {
Text("H: \(randomH)")
Text("S: \(randomS)")
Text("L: \(randomL)")
}
.fontWeight(.medium)
.foregroundColor(.white)
}
}
}
修正 View 的标识:id
尽管 View 没有供给 reload 办法,但是 View 供给了 id 办法绑定 View 的身份标识。
extension View {
/// Binds a view's identity to the given proxy value.
///
/// When the proxy value specified by the `id` parameter changes, the
/// identity of the view — for example, its state — is reset.
@inlinable public func id<ID>(_ id: ID) -> some View where ID : Hashable
}
因而咱们能够通过修正一个 View 的 id 的值来告诉体系这个 View 已经变化,需求从头改写。
咱们能够把要改写的 View 的 id 绑定到一个时间戳上面。每次要更新的时分对 ViewId 从头赋值就能够了。
沿用上一节的代码,完成是这样的:
struct ContentView: View {
@State private var refreshViewId = Date().timeIntervalSince1970
var body: some View {
VStack {
RandomView()
.frame(width: 150, height: 150)
.id(refreshViewId)
Button("改写") {
updateViewModel()
}
}
}
private func updateViewModel() {
refreshViewId = Date().timeIntervalSince1970
}
}