Search code examples
iosswiftgoogle-mapsuipopovercontroller

How to get the UIView instance for a Google Map marker?


I want to show a VC as a pop up when the user taps on one of the markers on the Google Map.

The reason that I want to do this is because I want to control the view that pops up when the marker is tapped. I tried using the mapView(mapView: GMSMapView, markerInfoWindow marker: GMSMarker) delegate method. But I don't know how to create a view controller in that method that controls the marker info window's view.

To present a VC as a pop over, I did this:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MarkerInfoController")
vc.modalInPopover = true
vc.modalPresentationStyle = .Popover
print(marker.iconView)
vc.popoverPresentationController!.sourceView = marker.iconView

self.presentVC(vc) // this is from EZSwiftExtensions. Don't worry about it

The problem arises when I try to set the sourceView of the UIPopoverPresentationController. I thought using the iconView property would work, but no. There is always an error saying that sourceView is not set.

How can I get the UIView instance for the marker, so that I can assign it to sourceView?

P.S. This is how a marker is created:

func mapView(mapView: GMSMapView, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D) {
    let marker = GMSMarker(position: coordinate)
    marker.map = mapView
}

Solution

  • Output: enter image description here

    Code:

    import UIKit
    import GoogleMaps
    
    class MapViewController: UIViewController {
      
      @IBOutlet weak var mapView: GMSMapView!
      var sourceView: UIView?
    }
    
    extension MapViewController: GMSMapViewDelegate {
      
      func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
        mapCenterPinImage.fadeOut(0.25)
        
        // Adding a delay becuase when click on marker Camera changes it position
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
          
          let location = marker.accessibilityActivationPoint
          self.sourceView = UIView(frame: CGRect(x: location.x, y: location.y, width: 1, height: 1))
          self.view.addSubview(self.sourceView!)
        
          let popController = MyPopUpViewController()
          popController.modalPresentationStyle = UIModalPresentationStyle.popover
          popController.preferredContentSize = CGSize(width: 200, height: 200)
          popController.popoverPresentationController?.delegate = self
          popController.popoverPresentationController?.sourceView = self.sourceView
          self.present(popController, animated: true)
        }
    
        return false
      }
      
    }
    extension MapViewController: UIPopoverPresentationControllerDelegate{
      func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return .none
      }
      func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
        sourceView?.removeFromSuperview()
        sourceView = nil
        return true
      }
      
    }
    

    What I've done basically created a UIView and added it to ViewController at runtime and set this as a source of Popup and make it nil when it's dismissed. marker.accessibilityActivationPoint is the source of X and Y according to device's screen