将SwiftUI视图呈现为更深层次的导航级别的UIImage。

huangapple go评论81阅读模式
英文:

Rendering SwiftUI View to UIImage at a deeper navigation level

问题

我需要将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为图像?

英文:

I need to render a SwiftUI View to an UIImage without displaying it for sharing purposes, but the solutions I found here are not working if I do the rendering in a View referred by a NavigationLink.

Here is a minimal example for reproducing my problem:

SampleView.swift (the one I need rendered as 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)
        }
    }
}

The SampleView will be rendered correctly at my ContentView, but is rendered to a blank image at my SubContentView.

Xcode is showing following error message on output

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.

How to render my SampleView correctly to an image from the SubContentView?

答案1

得分: 2

从日志消息看,当您调用getImage时,它似乎正处于Core Animation事务的中间阶段(以显示SubContentView),这导致无法绘制视图。在显示ContentView时,可能没有事务,这可能是因为它是根视图。

因此,我尝试将getImage调用放入DispatchQueue.main.async中。思路是允许主队列完成事务,然后才绘制视图。这样可以正常工作。

struct SubContentView: View {
    
    @State var image: UIImage?
    
    var body: some View {
        VStack {
            Text("SubContentView")
            if let image = image {
                Image(uiImage: image)
            }
        }.onAppear {
            DispatchQueue.main.async {
                self.image = SampleView().getImage()
            }
        }
    }
}
英文:

From the log message, it seems like at the time that you call getImage, it is in the middle of a Core Animation transaction (in order to show the SubContentView), and that makes it unable to draw the view. There was no transaction when showing the ContentView, probably because it is the root.

Therefore, I tried putting the getImage call inside DispatchQueue.main.async. The idea is to allow the main queue to finish the transaction, and only then draw the view. This worked.

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()
            }
        }
    }
}

huangapple
  • 本文由 发表于 2023年8月5日 06:05:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76839327.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定