我如何确定视图在 SwiftUI 中的最后一行代码之前完全渲染?

2024-05-01

我有一些代码,它们必须在视图完全渲染和绘制后被触发,因为我们知道视图的 onAppear 或 onChange ,它们对于了解视图是否已出现或正在更改很有用,但它们是确保视图已 100% 渲染没有用,例如,如果我们在视图中获得 ForEach、List 或 Form,您可以看到视图,但由于层次结构,ForEach 仍然可以在视图上工作,因此这意味着视图确实未完全加载,如果您提供动画修改器,那么您也可以看到它,它可能会变得更加明显,所以我的目标是知道如何 100% 确定我的视图会渲染其中的所有内容,并且不再需要运行代码来渲染视图?

感谢您的阅读和帮助


Example:

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可以决定做任何它想做的事。

考虑到这一点(假设渲染==出现),您可以采取的方法是“跟踪”您关心的那些“出现”的视图,并在它们全部出现时触发回调。

您可以创建一个视图修改器来跟踪每个视图的“渲染”状态,并使用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")
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我如何确定视图在 SwiftUI 中的最后一行代码之前完全渲染? 的相关文章

  • SwiftUI:如何让项目的拖放重新排序起作用?

    我有以下 SwiftUI 视图 struct ContentView View State var model Model var body some View ScrollView LazyVGrid columns columns sp
  • Swift UI 导出画布内容

    我有一个画布 用户可以在上面画东西 我想导出用户在画布上绘制的任何内容 并且我正在使用以下扩展从视图中获取图像 extension View func snapshot gt UIImage let controller UIHosting
  • 捕获 SwiftUI 中的错误

    我在某些视图中有一个按钮 它调用 ViewModel 中可能引发错误的函数 Button action do try self taskViewModel createInstance name self name catch Databa
  • SwiftUI - 如何编辑列表中的行?

    我想使用 EditButton 切换编辑模式 并将列表行切换到编辑模式 我想在编辑模式下包含一个用于打开模式的新按钮 我什至根本无法获取 EditMode 值来切换行内容 struct ContentView View Environmen
  • 在 SwiftUI 中使用获取视图的宽度

    我需要获取渲染视图的宽度SwiftUI 这显然没那么容易 我的看法是 我需要一个返回视图尺寸的函数 就这么简单 var body some View VStack alignment leading Text timer name font
  • 剪裁为形状的 SwiftUI 图像在上下文菜单中具有透明填充

    在我的 SwiftUI 应用程序中 我的资产目录中有一张宽高比为 1 1 的图像 在我的代码中 我有一个Image使用不同的宽高比查看 将图像裁剪为新尺寸 Image My Image resizable aspectRatio conte
  • 我想为 TabBar 设置背景

    I don t know how to change the background of the TabBar by an Image I try to change the background of TabBar not try to
  • 在 SwiftUI 文档应用程序中,如何从函数内保存文档

    当前版本的 Xcode 版本 12 5 1 为 macOS 的基于文档的应用程序提供了一个模板 提供以下文档模型 struct MyDocument FileDocument var text String init text String
  • SwiftUI 图像 ClipsToBounds

    尝试使用 SwiftUI Xcode 11 0 beta 2 我尝试用图像填充视图 Image large resizable aspectRatio contentMode fill frame width 80 height 80 al
  • WidgetKit 并发症不会更新

    我们正在迁移ClockKit并发症WidgetKit在我们的手表应用程序中 watchOS 9 迁移很顺利 UI部分工作得很好 然而 我们遇到了小部件在手表应用程序请求时未更新的问题 我相信我们错过了一些非常简单和基本的东西 但到目前为止还
  • SwiftUI 有模糊背景的方法吗?

    我希望模糊视图的背景 但不想必须突破 UIKit 才能完成它 例如 UIVisualEffectView 我正在翻阅文档却一无所获 似乎没有办法实时剪辑背景并对它应用效果 我错了还是以错误的方式看待它 1 Native SwiftUI方式
  • 使 Picker 与其他 BinaryInteger 类型兼容

    Picker仅当与以下一起使用时才能正常工作Int 当使用任何其他类型的BinaryInteger它根本不更新选择 为了解决这个问题 我想做一个CompatilibityPicker但我必须承认我的理解Binding实际上工作给我带来了很多
  • SwiftUI 表单中的动态行高

    我正在向 SwiftUI 表单添加控件以帮助用户输入数据 并限制条目 尽管 Forms 有很多值得喜欢的地方 但我发现在该容器之外运行良好的东西在容器内却会发生非常意想不到的事情 并且如何弥补这一点并不总是显而易见的 计划是将数据字段显示为
  • SwiftUI:获取动态背景颜色(深色模式或浅色模式)

    有没有一种方法可以系统地访问 SwiftUI 视图的标准动态背景颜色 无论用户处于浅色模式还是深色模式 例如 我知道以下内容可用于获取主要 例如文本 颜色 let textColor Color primary 但我没有看到任何类似的背景颜
  • Xcode 12 根本没有调用动态链接 Firebase 函数?

    因此 我有一个正在运行的动态链接 当我单击它时它会打开应用程序 但不会发生动态链接的处理 这是因为下面看到的应用程序功能从未输入过 我不知道为什么 func handleIncomingDynamicLink dynamicLink Dyn
  • 如何在 SwiftUI 中仅使用 ForEach 而不是列表来滑动删除

    我正在 SwiftUI 中使用 ForEach 制作自定义列表 我的目标是进行滑动删除手势 而不是将 ForEach 嵌入到列表中 到目前为止 这是我的代码 import SwiftUI struct ContentView View le
  • SwiftUI 意外地自动弹出 NavigationLink

    我有一个简单的用例 其中一个屏幕使用 NavigationLink 推送另一个屏幕 iOS 14 5 有一个奇怪的行为 即推送的屏幕在被推送后立即弹出 Code NavigationLink destination EmptyView Em
  • 为什么选择选择器选项后我的 SwiftUI 页面标题会发生变化?

    struct SettingsView View let settings Setting Setting name Aperture Increments options 1 3 1 2 1 Setting name Shutter Sp
  • 等高的 SwiftUI HStack

    我想要Text 111 具有相同的高度VStack包含 2222 和 333 struct Test7 View var body some View HStack alignment top Text 111 Shall have equ
  • 只有根级导航目的地对于具有同质路径的导航堆栈有效

    我正在尝试整合NavigationStack在我的 SwiftUI 应用程序中 我有四个看法 CealUIApp OnBoardingView UserTypeView and RegisterView 我想从OnBoardingView

随机推荐