0

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.

Screen display example

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?

apps2go
  • 86
  • 1
  • 6

0 Answers0