Render SwiftUI View as an UIImage

I am wondering why people say your question is not clear. It actually makes perfect sense and it's one of the things I've been looking to do myself.

I finally found a way to do things the same way you wish them to be done, it's convoluted but it does work.

The idea is to abuse your second possibility (UIWindow.rootViewController). That one is fun because you take your window, you figure out what you wish to draw, and you draw it.

But the problem is this is your main window, and you ask to draw your main window.

The way I finally got it working is by doing a UIViewControllerRepresentable, which gives me a UIViewController in my SwiftUI application. Then, inside it, I put a single UIHostingController, which gives me a SwiftUI view inside the UIView. In other words, I do a bridge.

In the update function, I can then call a dispatch async to view.layer.render(context) to draw the image.

Of interest, the UIViewControllerRepresentable will actually be full screen. So I recommend doing a .scale(...) so your entire list fits in the screen (the render command will not mind it being smaller) and it will be centered. So if you know the size of your image in advance, you can do a HStack { VStack { YourStuff Spacer() } Spacer() } so it's rendered top-left.

Good luck!


Would something like this work for you?

import SwiftUI

extension UIView {
    func takeScreenshot() -> UIImage {
        // Begin context
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
        // Draw view in that context
        drawHierarchy(in: self.bounds, afterScreenUpdates: true)
        // And finally, get image
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        if (image != nil) {
            UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil);
            return image!
        }

        return UIImage()
    }
}

struct ContentView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let someView = UIView(frame: UIScreen.main.bounds)
        _ = someView.takeScreenshot()
        return someView
    }

    func updateUIView(_ view: UIView, context: Context) {

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}