拍摄 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
}
}
我正在尝试在 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
}
}