How to handle Tap's Event on Google Maps in SwiftUI

Viewed 836

I'm new in iOS Development. I'm develop an app that have a maps inside it. I want to know how to handle Tap gesture when the user clicks on the map.

My apps workflow is when user clicks somewhere in maps, a marker will be shown and when marker is tapped, the marker will show an overlay detail about that address.

Here is my code to show a maps

import SwiftUI
import GoogleMaps

struct GoogleMapsView: UIViewRepresentable {
    @ObservedObject var locationManager = LocationManager()
    private let zoom: Float = 15.0
    private let longitudeTest: CLLocationDegrees = 106.7587855
    private let latitudeTest: CLLocationDegrees = -6.2715794
    let marker : GMSMarker = GMSMarker()

    
    
    func makeUIView(context: Self.Context) -> GMSMapView {
        let camera = GMSCameraPosition.camera(withLatitude: latitudeTest, longitude: longitudeTest, zoom: zoom)

        let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
        
        return mapView
    }
    
    func updateUIView(_ mapView: GMSMapView, context: Context) {                
        marker.position = CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest)
        marker.title = "hay"
        marker.snippet = "hello"
        marker.map = mapView
        
        mapView.animate(toLocation: CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest))
                
    }
}
1 Answers

I found a solution for this. Just make a coordinator class and implement makeCoordinator function in UIViewRepresentable.

import SwiftUI
import GoogleMaps

struct GoogleMapsView: UIViewRepresentable {    
    @Binding var streetLocation: String
    @Binding var isFocused: Bool
    @Binding var requestSearch: Bool
    @Binding var searchAddress: String
    @State var longitudeTest: Double = 106.7587855
    @State var latitudeTest: Double = -6.2715794
    @ObservedObject var locationManager = LocationManager()
    private let zoom: Float = 15.0
    
    @State var selectedMarker: GMSMarker? = GMSMarker()
    
    func makeCoordinator() -> MapCoordinator {
        return MapCoordinator(
            parent: self,
            marker: $selectedMarker,
            latitude: $latitudeTest,
            longitude: $longitudeTest)
    }
    
    func makeUIView(context: Self.Context) -> GMSMapView {
        let camera = GMSCameraPosition.camera(withLatitude: latitudeTest, longitude: longitudeTest, zoom: zoom)
        
        let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
        mapView.delegate = context.coordinator
        
        selectedMarker!.position = CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest)
        selectedMarker!.title = "Address"
        selectedMarker!.snippet = ""
        selectedMarker!.map = mapView
        
        return mapView
    }
    
    func updateUIView(_ mapView: GMSMapView, context: Context) {
        //        let camera = GMSCameraPosition.camera(withLatitude: locationManager.latitude, longitude: locationManager.longitude, zoom: zoom)
        //        mapView.camera = camera
        selectedMarker!.position = CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest)
        selectedMarker!.snippet = streetLocation
        
        mapView.animate(toLocation: CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest))
        getAddress(latitude: latitudeTest, longitude: longitudeTest)
        
        if isFocused {
            mapView.animate(toLocation: CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest))
        }
        
        if requestSearch {
            DispatchQueue.main.async {
                getLatLongFromAddress(address: searchAddress) { (result) in
                    if result {
                        selectedMarker!.position = CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest)
                        selectedMarker!.snippet = streetLocation
                        mapView.animate(toLocation: CLLocationCoordinate2D(latitude: latitudeTest, longitude: longitudeTest))
                    } else {
                        print("no location found")
                    }
                }
            }
        }
    }
    
    func getAddress(latitude: Double, longitude: Double){
        
        let geocoder = GMSGeocoder()
        let coordinate = CLLocationCoordinate2DMake(Double(latitude), Double(longitude))
        
        geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
            if let address = response?.firstResult() {
                streetLocation = address.lines![0]
            }
        }
    }
    
    func getLatLongFromAddress(address: String, completion: @escaping((Bool) -> ())) {
        let geoCoder = CLGeocoder()
        geoCoder.geocodeAddressString(address) {
            placemarks, error in
            
            if placemarks != nil {
                let placemark = placemarks?.first
                latitudeTest = (placemark?.location?.coordinate.latitude)!
                longitudeTest = (placemark?.location?.coordinate.longitude)!
                completion(true)
                // Use your location
            } else {
                print("no location found")
                completion(false)
            }
        }
    }
    
    func searchAddress(latitude: Double, longitude: Double){
        
        let geocoder = GMSGeocoder()
        let coordinate = CLLocationCoordinate2DMake(Double(latitude), Double(longitude))
        
        geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
            if let address = response?.firstResult() {
                streetLocation = address.lines![0]
            }
        }
    }
}

class MapCoordinator: NSObject, GMSMapViewDelegate {
    // 1.
    let parent: GoogleMapsView       // access to owner view members,
    @Binding var selectedMarker: GMSMarker?
    @Binding var latitude: Double
    @Binding var longitude: Double
    
    init(parent: GoogleMapsView, marker: Binding<GMSMarker?>, latitude: Binding<Double>, longitude: Binding<Double>) {
        self.parent = parent
        _selectedMarker = marker
        _latitude = latitude
        _longitude = longitude
        
        print("init called")
    }
    
    deinit {
        print("deinit: MapCoordinator")
    }
    
    //    func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
    //
    //        print("A marker has been touched
    //        return true
    //
    //    }
    
    func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
        print("You tapped at \(coordinate.latitude), \(coordinate.longitude)")
        longitude = coordinate.longitude
        latitude = coordinate.latitude
    }
    
}
Related