I am experimenting with Google Maps SDK for iOS (v16.4) and using SwiftUI. I have set up a View implementing UIViewRepresentable and am using the @Binding property wrapper to set map properties. Everything is working well but I cannot seem to find a way to set the camera position such the whole of the given rectangle defined by the visibleRegion
property. I need the region to be correctly orientated so that long side is parallel to the long side of the display and the zoom level is set to maximise the size of the rectangle to fit within the screen bounds. The bearing of the long sides can be any angle relative to North and can be computed from the coordinates of the corners.
Here is the code of the View -
import SwiftUI
import GoogleMaps
struct GoogleMapsView: UIViewRepresentable {
@EnvironmentObject var locationManager: LocationManager
@Binding var zoom: Float
@Binding var mapType: GMSMapViewType
@Binding var bearing: CLLocationDirection
@Binding var target: CLLocationCoordinate2D
@Binding var visibleRegion: GMSVisibleRegion?
// MARK: UIViewRepresentable Protocol Methods
func makeUIView(context: Self.Context) -> GMSMapView {
let camera = GMSCameraPosition.camera(withTarget: target, zoom: zoom, bearing: bearing, viewingAngle: 0)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.delegate = context.coordinator
mapView.isMyLocationEnabled = true
return mapView
}
func updateUIView(_ mapView: GMSMapView, context: Context) {
if (mapView.mapType != mapType) {
mapView.mapType = mapType
}
if mapView.camera.zoom != self.zoom {
mapView.animate(toZoom: self.zoom)
}
if mapView.camera.bearing != self.bearing {
mapView.animate(toBearing: self.bearing)
}
if mapView.camera.target != self.target {
mapView.animate(toLocation: self.target)
}
// This shows the rectangle but not correctly oriented
if let region = self.visibleRegion, region != mapView.projection.visibleRegion() {
let bounds = GMSCoordinateBounds(region: region)
mapView.animate(with: GMSCameraUpdate.fit(bounds))
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
// MARK: GMSMapViewDelegate
class Coordinator: NSObject, GMSMapViewDelegate {
let parent: GoogleMapsView
init(_ parent: GoogleMapsView) {
self.parent = parent
}
func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
let region = mapView.projection.visibleRegion();
print("You tapped the map at (\(coordinate.latitude), \(coordinate.longitude))")
print("Map display info:")
print("Centre target: \(mapView.camera.target)")
print("Visible region: \(region)")
print("Bearing: \(mapView.camera.bearing)")
print("Zoom: \(mapView.camera.zoom)\n")
}
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
let region = mapView.projection.visibleRegion();
if parent.visibleRegion == nil || parent.visibleRegion! != region {
parent.visibleRegion = region
}
if parent.zoom != mapView.camera.zoom {
parent.zoom = mapView.camera.zoom
print("Current zoom: \(parent.zoom)")
}
if parent.bearing != mapView.camera.bearing {
parent.bearing = mapView.camera.bearing
}
if parent.target != mapView.camera.target {
parent.target = mapView.camera.target
}
}
}
}
I have tried setting the bearing after setting the visibleRegion but I don't know how to set the correct zoom so that the whole rectangular region is visible.
Can anyone suggest how this can be achieved?