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

前端 未结 4 589
醉梦人生
醉梦人生 2020-12-08 22:34

Similar to this thread

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

4条回答
  •  盖世英雄少女心
    2020-12-08 23:06

    I came up with a solution when you can save to UIImage a SwiftUI View that is not on the screen. The solution looks a bit weird, but works fine.

    First create a class that serves as connection between UIHostingController and your SwiftUI. In this class, define a function that you can call to copy your "View's" image. After you do this, simply "Publish" new value to update your views.

    class Controller:ObservableObject {
         
        @Published var update=false
        
        var img:UIImage?
        
        var hostingController:MySwiftUIViewHostingController?
        
        init() {
    
        }
        
        func copyImage() {
            img=hostingController?.copyImage()
            update=true
        }
    }
    

    Then wrap your SwiftUI View that you want to copy via UIHostingController

    class MySwiftUIViewHostingController: UIHostingController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        func copyImage()->UIImage {
            let renderer = UIGraphicsImageRenderer(bounds: self.view.bounds)
            
            return renderer.image(actions: { (c) in
                self.view.layer.render(in: c.cgContext)
            })
        }
        
    }
    

    The copyImage() function returns the controller's view as UIImage

    Now you need to present UIHostingController:

    struct MyUIViewController:UIViewControllerRepresentable {
        
        @ObservedObject var cntrl:Controller
        
        func makeUIViewController(context: Context) -> MySwiftUIViewHostingController {
            let controller=MySwiftUIViewHostingController(rootView: TestView())
            cntrl.hostingController=controller
            return controller
        }
        
        func updateUIViewController(_ uiViewController: MySwiftUIViewHostingController, context: Context) {
            
        }
        
    }
    

    And the rest as follows:

    struct TestView:View {
        
        var body: some View {
            VStack {
                Text("Title")
                Image("img2")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                Text("foot note")
            }
        }
    }
    
    import SwiftUI
    
    struct ContentView: View {
        @ObservedObject var cntrl=Controller()
        var body: some View {
            ScrollView {
                VStack {
                    HStack {
                        Image("img1")
                            .resizable()
                            .scaledToFit()
                            .border(Color.black, width: 2.0)
                            .onTapGesture(count: 2) {
                                print("tap registered")
                                self.cntrl.copyImage()
                        }
                        Image("img1")
                            .resizable()
                            .scaledToFit()
                            .border(Color.black, width: 2.0)
                    }
                    
                    TextView()
                    ImageCopy(cntrl: cntrl)
                        .border(Color.red, width: 2.0)
                    TextView()
                    TextView()
                    TextView()
                    TextView()
                    TextView()
                    MyUIViewController(cntrl: cntrl)
                        .aspectRatio(contentMode: .fit)
                }
                
            }
        }
    }
    
    struct ImageCopy:View {
        @ObservedObject var cntrl:Controller
        var body: some View {
            VStack {
                Image(uiImage: cntrl.img ?? UIImage())
                    .resizable()
                    .frame(width: 200, height: 200, alignment: .center)
            }
            
        }
    }
    
    struct TextView:View {
        
        var body: some View {
            VStack {
                Text("Bla Bla Bla Bla Bla ")
                Text("Bla Bla Bla Bla Bla ")
                Text("Bla Bla Bla Bla Bla ")
                Text("Bla Bla Bla Bla Bla ")
                Text("Bla Bla Bla Bla Bla ")
                
            }
            
        }
    }
    
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    
    

    You need img1 and img2 (the one that gets copied). I put everything into a scrollview so that one can see that the image copies fine even when not on the screen.

提交回复
热议问题