英文:
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()
}
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论