AFAIK,没有通用的方法来判断所有可能的后代视图何时“出现”(即会解雇他们的onAppear
).
根据您的想法,“出现”与“呈现”不同。一般来说,每个视图决定何时渲染其子视图。例如,LazyVStack
只会在需要渲染时创建其元素。自定义视图符合UIViewControllerRepresentable
可以决定做任何它想做的事。
考虑到这一点(假设渲染==出现),您可以采取的方法是“跟踪”您关心的那些“出现”的视图,并在它们全部出现时触发回调。
您可以创建一个视图修改器来跟踪每个视图的“渲染”状态,并使用PreferenceKey
收集所有这些数据:
struct RenderedPreferenceKey: PreferenceKey {
static var defaultValue: Int = 0
static func reduce(value: inout Int, nextValue: () -> Int) {
value = value + nextValue() // sum all those remain to-be-rendered
}
}
struct MarkRender: ViewModifier {
@State private var toBeRendered = 1
func body(content: Content) -> some View {
content
.preference(key: RenderedPreferenceKey.self, value: toBeRendered)
.onAppear { toBeRendered = 0 }
}
}
然后,创建便捷方法View
简化其用法:
extension View {
func trackRendering() -> some View {
self.modifier(MarkRender())
}
func onRendered(_ perform: @escaping () -> Void) -> some View {
self.onPreferenceChange(RenderedPreferenceKey.self) { toBeRendered in
// invoke the callback only when all tracked have been set to 0,
// which happens when all of their .onAppear are called
if toBeRendered == 0 { perform() }
}
}
}
用法是:
VStack {
ForEach(0..<3, id:\..self) { index in
Text("\(index)").trackRendering()
}
}
.onRendered {
print("Rendered")
}