Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何确保视图在SwiftUI中的最后一行代码之前都已完全呈现?_Swiftui - Fatal编程技术网

如何确保视图在SwiftUI中的最后一行代码之前都已完全呈现?

如何确保视图在SwiftUI中的最后一行代码之前都已完全呈现?,swiftui,Swiftui,我有一些代码,它们必须在视图完全渲染和绘制后被激发,因为我们知道我们看到或更改了一个视图,它们可以有用地知道视图是否已出现或正在更改,但它们没有用处,无法确保视图已100%渲染,例如,如果我们得到ForEach,在视图中的列表或窗体中,您可以看到视图,但由于层次结构仍然可以在视图上进行操作,因此这意味着视图没有完全加载,如果您提供动画修改器,那么您也可以看到它,它可能会变得更加明显,因此,我的目标是了解如何100%确保视图中的所有内容都得到渲染,并且不再需要运行行代码来渲染视图? 谢谢你的阅读和

我有一些代码,它们必须在视图完全渲染和绘制后被激发,因为我们知道我们看到或更改了一个视图,它们可以有用地知道视图是否已出现或正在更改,但它们没有用处,无法确保视图已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,你能详细说明这个问题吗?(我修正了一个小的复制粘贴错误)