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