拍摄 Google 地图的快照并发送到 SwiftUI 中的相册

Take Google Maps' snapshot and send to Photo Album in SwiftUI

我正在尝试在 SwiftUI 中捕获 Google 地图快照,但似乎我无法弄清楚我没有得到什么,尽管我的猜测是我快到了。

当我单击相机 FAB 时,我的应用程序必须在我的设备相册中创建一个 png 文件。问题是:图片是一个白色的正方形。

完整代码如下:

import Foundation
import SwiftUI
import GoogleMaps

struct HomeScreenshot: View {
    var btnTake : some View { Button(action: {

        // HERE'S WHERE A KNOW I MUST DO SOMETHING, BUT JUST CAN'T FIGURE OUT WHAT! :-(
        // I'VE FOUND ON Whosebug THE LOGIC BELOW, BUT IT'S NOT WORKING AS I NEED


        // THEORETICALLY, THIS SHOULD CAPTURE THE WHOLE SCREEN TO AN UIVIEW
        let someView = UIView(frame: UIScreen.main.bounds)

        // AND CONVERT INTO AN UIIMAGE
        let imagem = someView.takeScreenshot()

        // AND THEN GENERATE THE PNG FILE ON DEVICE'S DOCUMENTS DIRECTORY
        if let data = imagem.pngData() {

            let filename = Utilitarios().getDocumentsDirectory().appendingPathComponent("image_file.png")

            try? data.write(to: filename)

            print("\(filename) successfully writen but in a figure of a white square")

            // THIS IS NOT WORKING. THE PNG FILE GENERATED IS A WHITE SQUARE ON IOS PHOTOS
        }
    }) {
            Image(systemName: "camera.fill")
                .resizable()
                .frame(width: AppDelegate.tamanhoIconePequeno, height: AppDelegate.tamanhoIconePequeno)
                .foregroundColor(Color.white)
            }
            .frame(width: AppDelegate.tamanhoFAB, height: AppDelegate.tamanhoFAB )
            .background(Color.orange)
            .cornerRadius(38.5)
            .padding(.bottom, 20)
            .padding(.trailing, 10)
            .shadow(color: Color.black.opacity(0.3),
                    radius: 3,
                    x: 3,
                    y: 3)
    }

    var body: some View {
        ZStack() {
            GoogleMapsHomeScreenshot().edgesIgnoringSafeArea(.all)
            VStack{
                Spacer()
                HStack{
                    Spacer()
                    btnTake
                }
            }.padding()
        }
        .navigationBarBackButtonHidden(true)
        .navigationBarTitle(Text("Snapshot test"), displayMode: .inline)
    }
}

struct HomeScreenshot_Previews: PreviewProvider {
    static var previews: some View {
        HomeScreenshot()
    }
}

这是 Google地图定义:

struct GoogleMapsHomeScreenshot: UIViewRepresentable {
    private let zoom: Float = 18

    // arbitrary coordinates, just for testing purposes
    let lat: Double = -15.6692660716233
    let lng: Double = -47.83980712156295

    func makeCoordinator() -> Coordinator {
        return Coordinator(
            owner: self
        )
    }

    class Coordinator: NSObject, GMSMapViewDelegate, ObservableObject {
        let owner: GoogleMapsHomeScreenshot
        init( owner: GoogleMapsHomeScreenshot ) {
            self.owner = owner
        }         
    }

    func makeUIView(context: Self.Context) -> GMSMapView {
        let camera = GMSCameraPosition.camera(
            withLatitude: lat,
            longitude: lng,
            zoom: zoom)
        let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
        mapView.mapType = .hybrid
        mapView.delegate = context.coordinator              
        return mapView
    }

    func updateUIView(_ mapView: GMSMapView, context: Context) {    
    }
}

最后,这扩展了 UIView 以拍摄快照(这是我认为我的问题所在)。

extension UIView {
    func takeScreenshot() -> UIImage {

        // Begin context
        UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size, false, UIScreen.main.scale)

        // Draw view in that context
        drawHierarchy(in: UIScreen.main.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: View {
    let map = GMSMapView.map(withFrame: CGRect.zero, camera: GMSCameraPosition.camera(withLatitude: 16.8409, longitude: 96.1735, zoom: 6.0)) // This is GMSMapView object to share its copy to MapView.
    var body: some View {
        ZStack(alignment: .bottomTrailing) {
            MapView(mapView: map)
            Button(action: {
                self.saveToLibrary() // It save the capture of the current position of map
            }) {
                Circle()
                    .frame(width: 50, height: 50)
            }
            .padding()
            .padding(.bottom)
        }.edgesIgnoringSafeArea(.all)
    }
    func saveToLibrary() {
        let image = map.layer.makeSnapshot() // It captures a snapshot of current view
        guard let selectedImage = image else {
            return
        }
        UIImageWriteToSavedPhotosAlbum(selectedImage, nil, nil, nil)
    }
}

struct MapView: UIViewRepresentable {
    var mapView: GMSMapView
    func makeUIView(context: Self.Context) -> GMSMapView {
        return mapView
    }

    func updateUIView(_ mapView: GMSMapView, context: Self.Context) { }
}

extension CALayer {
    func makeSnapshot() -> UIImage? {
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
        defer { UIGraphicsEndImageContext() }
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        render(in: context)
        let screenshot = UIGraphicsGetImageFromCurrentImageContext()
        return screenshot
    }
}