Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
902 views
in Technique[技术] by (71.8m points)

swift - How to convert a View (not UIView) to an image?

Similar to this thread: How to convert a UIView to an image.

I would like to convert a SwiftUI View rather than a UIView to an image.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Although SwiftUI does not provide a direct method to convert a view into an image, you still can do it. It is a little bit of a hack, but it works just fine.

In the example below, the code captures the image of two VStacks whenever they are tapped. Their contents are converted into a UIImage (that you can later save to a file if you need). In this case, I am just displaying it below.

Note that the code can be improved, but it provides the basics to get you started. I use GeometryReader to get the coordinates of the VStack to capture, but it could be improved with Preferences to make it more robust. Check the links provided, if you need to learn more about it.

Also, in order to convert an area of the screen to an image, we do need a UIView. The code uses UIApplication.shared.windows[0].rootViewController.view to get the top view, but depending on your scenario you may need to get it from somewhere else.

Good luck!

enter image description here

And this is the code (tested on iPhone Xr simulator, Xcode 11 beta 4):

import SwiftUI

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

struct ContentView: View {
    @State private var rect1: CGRect = .zero
    @State private var rect2: CGRect = .zero
    @State private var uiimage: UIImage? = nil

    var body: some View {
        VStack {
            HStack {
                VStack {
                    Text("LEFT")
                    Text("VIEW")
                }
                .padding(20)
                .background(Color.green)
                .border(Color.blue, width: 5)
                .background(RectGetter(rect: $rect1))
                .onTapGesture { self.uiimage = UIApplication.shared.windows[0].rootViewController?.view.asImage(rect: self.rect1) }

                VStack {
                    Text("RIGHT")
                    Text("VIEW")
                }
                .padding(40)
                .background(Color.yellow)
                .border(Color.green, width: 5)
                .background(RectGetter(rect: $rect2))
                .onTapGesture { self.uiimage = UIApplication.shared.windows[0].rootViewController?.view.asImage(rect: self.rect2) }

            }

            if uiimage != nil {
                VStack {
                    Text("Captured Image")
                    Image(uiImage: self.uiimage!).padding(20).border(Color.black)
                }.padding(20)
            }

        }

    }
}

struct RectGetter: View {
    @Binding var rect: CGRect

    var body: some View {
        GeometryReader { proxy in
            self.createView(proxy: proxy)
        }
    }

    func createView(proxy: GeometryProxy) -> some View {
        DispatchQueue.main.async {
            self.rect = proxy.frame(in: .global)
        }

        return Rectangle().fill(Color.clear)
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.8k users

...