screenshot on iOS26

I had take screenshots by following code

let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
self.uiImage = window?.rootViewController?.view!.getImage(rect: rect)

View has two views. One is ImageView contains some image and overlay of image detection results with .overlay. another view is InfoView contains several info and button which above code fired. on iOS 17, I can take screenshots as I saw, but on iOS26, missing on image of ImageView. Overlay(detected rectangle) in Imageview and InfView can be taken. How can I take screenshots as I saw on iOS26?(iPad)

Hello junichi7,

Thank you for your question. Can you please reformat the above code in a Code Block for greater readability?

Thank you for your patience, Richard Yeh  Developer Technical Support

Code Block is as follows


let scenes = UIApplication.shared.connectedScenes

let windowScene = scenes.first as? UIWindowScene

let window = windowScene?.windows.first

self.uiImage = window?.rootViewController?.view!.getImage(rect: rect)


Hello junichi7,

Thank you very much for the cleaned up formatting! Much better. It appears you're calling getImage(rect:) - is this a custom function for a custom UIView subclass? Can you please provide the code for it? Also feel free to please attach a screenshot of the issue in your post.

If your goal is to create a UIImage, you could render the complete visible view hierarchy via drawHierarchy(in:afterScreenUpdates:) and then fetch the current currentImage via the UIGraphicsImageRendererContext.

Thank you for your patience,

Richard Yeh  Developer Technical Support

Thanks for your quick response.

My getImage(rect:) is following as extension UIView

 func getImage(rect: CGRect) -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: rect)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}

screen shot is not available today, later I will attached with some masking required.

My goal is to capture screen(UIImage) as I saw after detetion results overlayed on captured image and other UIView information such as date & time and my custom information. like default screen capture pressing hardware button.

Can you provide some short sample code that render the complete visible view hierarchy via drawHierarchy(in:afterScreenUpdates:) and then fetch the current currentImage via the UIGraphicsImageRendererContext.

screen shot is attached.

what I saw in display is image and detected rectangle, but screen capture image do not include image.

I solved this issue using following code, thanks for your advice

func captureScreenShot() -> UIImage? {
    guard let rootView = UIApplication.rootView() else {
        return nil
    }
    return rootView.captureHierarchyImage()
}

extension UIApplication {
    static func rootView() -> UIView? {
        guard let scene = shared.connectedScenes.first as? UIWindowScene,
              let window = scene.windows.first(where: { $0.isKeyWindow })
        else {
            return nil
        }
        return window.rootViewController?.view
    }
}

extension UIView {
    func captureHierarchyImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { _ in
            drawHierarchy(in: bounds, afterScreenUpdates: true)
        }
    }
}

Hello junichi7,

I'm happy to have helped you find a working solution!

Just one more suggestion about your code- since your app is for iPadOS, it is not recommended for you to fetch the first window of the first window scene and assume it is the current window scene. Because users might be running multiple instances of your app, with potentially multiple windows open for each instance (even if your app doesn't explicitly support multiple scenes), you want to think beyond the very first window scene of the app instance.

Rather, it is more useful to consider where is your window scene in the view hierarchy. You would do this by fetching the context of the view relevant to your code- in this case, the view you would like to screenshot. That context is vital for your code to understand which UIWindowScene or UIScreen it is related to. With that context, you can then get the window scene via view.window.windowScene or a similar property.

For example, if your app has a presenter layer that calls captureScreenShot(), then the presenter view controller should track the window scene. One possible way is to have a presenter per scene. You can then save the UIWindowScene on the presenter itself.

Thank you for your patience,

Richard Yeh  Developer Technical Support

Dear Richard

Thanks for your further advice.

I made followings, did I code what you said? or more other effective and simplified way available?

struct CaptureContainer<Content: View>: UIViewRepresentable {

    @Binding var hostView: UIView?
    let content: Content

    init(
        hostView: Binding<UIView?>,
        @ViewBuilder content: () -> Content
    ) {
        self._hostView = hostView
        self.content = content()
    }

    func makeUIView(context: Context) -> UIView {
        let container = UIView()
        container.backgroundColor = .white

        let hosting = UIHostingController(rootView: content)
        hosting.view.backgroundColor = .white
        hosting.view.translatesAutoresizingMaskIntoConstraints = false

        hosting.view.isUserInteractionEnabled = true

        container.addSubview(hosting.view)

        NSLayoutConstraint.activate([
            hosting.view.topAnchor.constraint(equalTo: container.topAnchor),
            hosting.view.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            hosting.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
            hosting.view.trailingAnchor.constraint(equalTo: container.trailingAnchor)
        ])

        DispatchQueue.main.async {
            self.hostView = hosting.view
        }

        return container
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

and My Home View is

struct HomeView: View {
    @State private var captureView: UIView?
    var body: some View {
        CaptureContainer(hostView: $captureView) {

            VStack {
                HStack {
                    ImageView()
                    InfoView(
                        hostView: $captureView
                    )
                }
                ActionView()
            }
        }
        .ignoresSafeArea()
    }
}

and

struct InfoView:View{
    @Binding var hostView: UIView?
    @State var uiImage: UIImage? = nil
    var body: some View {
        Button(action: {
            screenShot(captureView: hostView)
        }){
            Text("Save")
        }
    }
}

func screenShot(captureView:UIView?){
    self.uiImage  = captureScreenshot(captureView: captureView)
} 

func captureScreenshot(captureView:UIView?) -> UIImage? {
        guard let view = captureView else { return nil }
        return view.captureHierarchyImage()
}

extension UIView {
    func captureHierarchyImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { _ in
            drawHierarchy(in: bounds, afterScreenUpdates: true)
        }
    }
}
screenshot on iOS26
 
 
Q