I am attempting to capture a screenshot of my view in SwiftUI. I have tried with both the ImageRenderer(content: myview) and with the below snapshot View extension. On both cases it crashes giving the error . . .
Fatal error: No ObservableObject of type isActive found. A
View.environmentObject(_:) for isActive may be missing as
an ancestor of this view.
I have tried both an empty environment object and the object with variables and it always get the same error. Is there any way to allow the use of environment objects when programmatically capturing a screenshot?
//main view
struct TestView111: View {
var body: some View {
VStack{
otherview
//click this to capture screenshot and break on environment var
Button(action: {
let image = otherview.snapshot()
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}, label: {
Text("Save").buttonStyleBlue()
})
}
}
//view to take snapshot of
var otherview: some View {
TestView112()
}
}
//sub view
struct TestView112: View {
@EnvironmentObject private var objRect: GraphObjectRectList
var body: some View {
//can no longer find isActive here and breaks on btn click
ForEach(objRect.isActive.indices, id: \.self) { i in
Text(String(i))
}
}
}
//extension to take snapshot
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let size = CGSize(width: 500, height: 500)
view?.bounds = CGRect(origin: .zero, size: size)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
//my Environment class
class GraphObjectRectList: ObservableObject {
@Published var isActive: [Bool] = [true, true]
}
//Scene View
struct TestAppApp: App {
var body: some Scene {
WindowGroup {
TestView111()
.environmentObject(GraphObjectRectList())
}
}
}
Is the graphics rendering engine is unable to access the global object twice?
Thanks for any help!
>Solution :
In your current example, the EnvironmentObject doesn’t exist on otherview because otherview doesn’t exist in the view hierarchy — it exists on its own in the Button‘s action.
To solve this, inject it on the version you’re sending to snapshot:
struct TestView111: View {
@EnvironmentObject private var objRect: GraphObjectRectList //<-- Here
var body: some View {
VStack{
otherview //<-- This one has a reference to the object, since it's in the view hierarchy
Button(action: {
let image = otherview.environmentObject(objRect).snapshot() //<-- Here
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}, label: {
Text("Save")
})
}
}
//view to take snapshot of
var otherview: some View {
TestView112()
}
}