如何确保视图在SwiftUI中的最后一行代码之前都已完全呈现?
我有一些代码,它们必须在视图完全渲染和绘制后被激发,因为我们知道我们看到或更改了一个视图,它们可以有用地知道视图是否已出现或正在更改,但它们没有用处,无法确保视图已100%渲染,例如,如果我们得到ForEach,在视图中的列表或窗体中,您可以看到视图,但由于层次结构仍然可以在视图上进行操作,因此这意味着视图没有完全加载,如果您提供动画修改器,那么您也可以看到它,它可能会变得更加明显,因此,我的目标是了解如何100%确保视图中的所有内容都得到渲染,并且不再需要运行行代码来渲染视图? 谢谢你的阅读和帮助如何确保视图在SwiftUI中的最后一行代码之前都已完全呈现?,swiftui,Swiftui,我有一些代码,它们必须在视图完全渲染和绘制后被激发,因为我们知道我们看到或更改了一个视图,它们可以有用地知道视图是否已出现或正在更改,但它们没有用处,无法确保视图已100%渲染,例如,如果我们得到ForEach,在视图中的列表或窗体中,您可以看到视图,但由于层次结构仍然可以在视图上进行操作,因此这意味着视图没有完全加载,如果您提供动画修改器,那么您也可以看到它,它可能会变得更加明显,因此,我的目标是了解如何100%确保视图中的所有内容都得到渲染,并且不再需要运行行代码来渲染视图? 谢谢你的阅读和
例如:
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("- - - - - - - - - - -") }
}
}
导入快捷界面
结构ContentView:View{
var body:一些观点{
层次视图()
.onAppear(){print(“HierarchyView”);print(“-”)}
}
}
结构层次视图:视图{
var body:一些观点{
ZStack{
颜色
蓝色
.ignoresSafeArea()
.onAppear(){print(“blue”);print(“---”)}
VStack{
文本(“顶部文本”)
.onAppear(){print(“顶部文本”)}
垫片()
.onAppear(){print(“顶部间隔符”)}
}
.onAppear(){print(“Top-VStack”);print(“-”)}
VStack{
VStack{
VStack{
ForEach(0..抱歉,没有通用的方法来判断所有可能的后代视图何时“出现”(即在出现时启动它们的)
根据你的想法,“出现”和“呈现”是不同的。一般来说,每个视图决定何时呈现其子视图。例如,LazyVStack
仅在需要呈现元素时创建其元素。符合UIViewControllerRepresentable
的自定义视图可以决定执行其所需的任何操作
考虑到这一点(假设render==execute),您可以采取的一种方法是“跟踪”那些您关心“已出现”的视图,并在它们都出现时发出回调
您可以创建视图修改器来跟踪每个视图“渲染”状态,并使用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 }
}
}
然后,在视图
上创建方便的方法以简化其使用:
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")
}
VStack{
弗雷奇(0...onAppear
的父对象在其子对象初始化并计算其主体后被激发。我一直这么认为,直到我观察到ForEach的行为!父对象的子对象可以在其父对象之后进行渲染。在这种情况下,子对象是ForEach,您可以将其放入视图或VStack中,或者诸如此类,它将在最后进行渲染!具有bo层次结构ttom到顶部,最后一个索引到第一个索引!这使得很难找到真正完成的渲染,另一方面,我不想在ForEach中设置一个条件来检查这是否是索引零,因为这会使应用程序运行沉重,这只是ForEach,还有其他可能的方法来更改我所说的几何体,这就是为什么我想知道w、 当视图完全呈现时,它将不再需要运行行代码。无论我们在视图中使用了什么,它都可能是ForEach、几何体或简单文本,我需要找出了解的一般方法。我建议您提供一个最小的示例,说明您的意思以及它与您的期望的偏差。或者,甚至在此之前-您希望如何动画要工作,它不在哪里我以前没有遇到过你的问题,因为我不完全理解你的问题。我告诉过你父视图相对于其子视图的触发时间。它还取决于“渲染”的含义-一般来说,视图可能“出现”,但实际上是以后再呈现其内容。SwiftUI也有很多秘密的事情发生,还有许多反最佳实践。从一个最小的示例(或两个行为不同的示例)开始你的期望与现实脱节,以减少歧义,并从那里开始。谢谢,它有问题,我不能使用它。@swiftPunk,你能详细说明这个问题吗?(我修正了一个小的复制粘贴错误)