我有一些代码,它们必须在View完全渲染和绘制之后必须被解雇,正如我们所知道的,我们对某个View拥有onAppear或onChange,它们对于了解View是否已出现或正在更改中很有用,但是它们是确保视图已100%渲染没有用,例如,如果我们在视图中获得了ForEach,List或Form,则可以看到View,但是由于层次结构,ForEach仍可以在View上工作,所以这意味着View可以没有完全加载,如果您给它一个动画修改器,那么它也会变得更加引人注目,因此您也可以看到它,所以我的目标是知道我如何才能100%确保将所有内容渲染到我的View中,而不再行代码运行以渲染视图?
感谢您的阅读和帮助
例:
import SwiftUI
struct ContentView: View {
var body: some View {
HierarchyView()
.onAppear() { print("HierarchyView"); print("- - - - - - - - - - -") }
}
}
struct HierarchyView: View {
var body: some View {
ZStack {
Color
.blue
.ignoresSafeArea()
.onAppear() { print("blue"); print("- - - - - - - - - - -") }
VStack {
Text("Top text")
.onAppear() { print("Top Text") }
Spacer()
.onAppear() { print("Top Spacer") }
}
.onAppear() { print("Top VStack"); print("- - - - - - - - - - -") }
VStack {
VStack {
VStack {
ForEach(0..<3, id:\..self) { index in
Text(index.description)
.onAppear() { print(index.description); if (index == 0) { print("Last of second ForEach!!!") } }
}
}
.onAppear() { print("Middle VStack Inside DEEP"); print("- - - - - - - - - - -") }
}
.onAppear() { print("Middle VStack Inside"); print("- - - - - - - - - - -") }
}
.onAppear() { print("Middle VStack Outside"); print("- - - - - - - - - - -") }
VStack {
Spacer()
.onAppear() { print("Bottom Spacer") }
ForEach(0..<3, id:\..self) { index in
Text(index.description)
.onAppear() { print(index.description); if (index == 0) { print("Last of first ForEach!!!") } }
}
Text("Bottom text")
.onAppear() { print("Bottom Text") }
}
.onAppear() { print("Bottom VStack"); print("- - - - - - - - - - -") }
}
.onAppear() { print("ZStack of HierarchyView"); print("- - - - - - - - - - -") }
}
}
AFAIK没有通用的方法来告诉所有可能的后代视图何时“出现”(即会触发它们的视图onAppear
)。
根据您的想法,“出现”与“呈现”不同。一般而言,每个视图都决定何时渲染其子级。例如,LazyVStack
仅在需要渲染时创建其元素。符合的自定义视图UIViewControllerRepresentable
可以决定执行其所需的任何操作。
考虑到这一点(假设render ==出现),您可以采用的方法是“跟踪”您关心的“已出现”的视图,并在所有视图都触发时触发回调。
您可以创建一个视图修饰符来跟踪每个视图的“渲染”状态,并用于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")
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句