Search code examples
iosgoogle-mapsswiftuigoogle-maps-sdk-ios

Googlemaps delegate methods never fired in iOS SwiftUI


Intergated the Google maps via SPM and maps seems to loaded correctly with few markers on the map, but I wanted to know when the map is fully loaded and when the map is moved etc..

For that we can use the GoogleMaps delegate methods like mapViewDidFinishTileRendering(_ mapView: GMSMapView) & mapViewSnapshotReady(_ mapView: GMSMapView)

But those functions are never been called.

Here is my implementation

import UIKit
import GoogleMaps

class MapViewController: UIViewController {
    var options = GMSMapViewOptions()
    var map = GMSMapView()
    var isAnimating: Bool = false

    override func loadView() {
      super.loadView()
      options.camera = GMSCameraPosition.camera(withLatitude: 18.659553, longitude: 78.105868, zoom: 17.0)
      options.frame = self.view.bounds
      map = GMSMapView(options: options)
      self.view = map
    }
}

import Foundation
import SwiftUI
import GoogleMaps

struct MapViewControllerBridge: UIViewControllerRepresentable {
    
    @Binding var markers: [GMSMarker]
    @Binding var selectedMarker: GMSMarker?
    var onAnimationEnded: () -> ()
    var mapViewWillMove: (Bool) -> ()

    func makeUIViewController(context: Context) -> MapViewController {
        let uiViewController = MapViewController()
        uiViewController.map.delegate = context.coordinator
        return uiViewController
    }

    func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
        markers.forEach { $0.map = uiViewController.map }
        selectedMarker?.map = uiViewController.map
        animateToSelectedMarker(viewController: uiViewController)
    }
    
    func makeCoordinator() -> MapViewCoordinator {
      return MapViewCoordinator(self)
    }
    
    private func animateToSelectedMarker(viewController: MapViewController) {
      guard let selectedMarker = selectedMarker else {
        return
      }

      let map = viewController.map
      if map.selectedMarker != selectedMarker {
        map.selectedMarker = selectedMarker
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
          map.animate(toZoom: kGMSMinZoomLevel)
          DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            map.animate(with: GMSCameraUpdate.setTarget(selectedMarker.position))
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
              map.animate(toZoom: 12)
              DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
                onAnimationEnded()
              })
            })
          }
        }
      }
    }
    
    final class MapViewCoordinator: NSObject, GMSMapViewDelegate {
        var mapViewControllerBridge: MapViewControllerBridge
        
        init(_ mapViewControllerBridge: MapViewControllerBridge) {
            self.mapViewControllerBridge = mapViewControllerBridge
        }
        
        func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
            self.mapViewControllerBridge.mapViewWillMove(gesture)
        }
        
        func mapViewDidFinishTileRendering(_ mapView: GMSMapView) {
            print("Map Finished Rendering..")
        }
        
        func mapViewSnapshotReady(_ mapView: GMSMapView) {
            print("Map View Snapshot Ready..")
        }
    }
}

Calling the MapViewControllerBridge from the ContentView file

MapViewControllerBridge(markers: $markers, selectedMarker: $selectedMarker, onAnimationEnded: {
                  self.zoomInCenter = true
                }, mapViewWillMove: { (isGesture) in
                  guard isGesture else { return }
                  self.zoomInCenter = false
                })
                .ignoresSafeArea()

Solution

  • It seems to be working if I remove the loadView() and use init() instead for the MapViewController class.

    class MapViewController: UIViewController {
        var options = GMSMapViewOptions()
        var map = GMSMapView()
        var isAnimating: Bool = false
    
        init() {
          super.init(nibName: nil, bundle: nil)
          options.camera = GMSCameraPosition.camera(withLatitude: 18.659553, longitude: 78.105868, zoom: 17.0)
          options.frame = self.view.bounds
          map = GMSMapView(options: options)
          self.view = map
        }
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }