在更深层次的导航级别上将SwiftUI视图渲染为UIImage。

3

我需要将SwiftUI视图渲染为UIImage以便分享,但这里找到的解决方案如果我在被NavigationLink引用的视图中进行渲染则不起作用。

这是一个最小化的示例,用于重现我的问题:

SampleView.swift(我需要将其渲染为UIImage)

struct SampleView: View {
    var body: some View {
        Image(systemName: "globe").ignoresSafeArea()
    }
    
    func getImage() -> UIImage {
        let controller = UIHostingController(rootView: self)
        controller.view.bounds = CGRect(origin: .zero, size: CGSize(width: 100, height: 100))
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        return UIGraphicsImageRenderer(size: controller.view.layer.frame.size, format: format).image { context in
            controller.view.drawHierarchy(in: controller.view.layer.bounds, afterScreenUpdates: true)
        }
    }
}

ContentView.swift

struct ContentView: View {
    var image: UIImage
    
    init() {
        self.image = SampleView().getImage()
    }
    
    var body: some View {
        NavigationView {
            VStack {
                Text("MainContentView")
                Image(uiImage: self.image) //working
                NavigationLink(
                    destination: SubContentView()
                ) {
                    Text("NavigationLink")
                } // end of navigationLink
            } // end of vstack
        } // end of navigationview
    }
}

SubContentView.swift

struct SubContentView: View {
    
    var image: UIImage
    
    init() {
        self.image = SampleView().getImage()
    }
    
    var body: some View {
        VStack {
            Text("SubContentView")
            Image(uiImage: self.image)
        }
    }
}

SampleView 在我的 ContentView 中会被正确渲染,但在我的 SubContentView 中被渲染成了一张空白图片。

Xcode 在输出中显示以下错误信息:

2023-08-04 23:46:48.901870+0200 ViewRenderToImageTest[9929:192715] [Snapshotting] View (0x156f0e140, _TtGC7SwiftUI14_UIHostingViewV21ViewRenderToImageTest10SampleView_) drawing with afterScreenUpdates:YES inside CoreAnimation commit is not supported.

如何从SubContentView正确地将我的SampleView渲染为图像?

@workingdogsupportUkraine 我将getImage函数移动到一个带有静态函数的辅助类中 class ViewHelper {public static func getImage(v: some View) -> UIImage {...},但仍然得到相同的结果(在SubContentView中显示空白图像)。 我还尝试将getImage函数移动到View的扩展中 (extension View { public func getImage() -> UIImage {...),这是大多数其他问题中建议的方法,但在SubContentView中仍然只能得到一个空白图像。 - undefined
是的,我也尝试了所有这些选项,但仍然没有成功,这就是为什么我删除了我的评论。请注意,我没有收到任何错误消息,只是在SubContentView中没有图像。 - undefined
1个回答

2
从日志信息来看,当您调用getImage时,它正处于一个核心动画事务的中间(为了显示SubContentView),这使得它无法绘制视图。在显示ContentView时没有事务,可能是因为它是根视图。
因此,我尝试将getImage调用放在DispatchQueue.main.async内部。这个想法是允许主队列完成事务,然后再绘制视图。这样做是有效的。
struct SubContentView: View {
    
    @State var image: UIImage?
    
    var body: some View {
        VStack {
            Text("SubContentView")
            if let image {
                Image(uiImage: image)
            }
        }.onAppear {
            DispatchQueue.main.async {
                image = SampleView().getImage()
            }
        }
    }
}

感谢您指出图像创建需要异步进行。这在演示项目中对我很有帮助。 - undefined
我接受了这个答案,因为它完全解决了我的演示项目中的问题。当我将主项目调整为使用这个解决方案时,图像创建工作得非常完美,但仍然会收到错误消息。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接