1
votes

I've made a custom view to be shown when a user taps on marker on google map. So I've wrote the delegate method markerInfoWindow as:

func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {

        let infoWindow = Bundle.main.loadNibNamed("emergencyInfo", owner: self.view, options: nil)!.first! as! emergencyInfo

        infoWindow.frame = CGRect(x: 0, y: 0, width: 200, height: 110)
        infoWindow.titleOfCenter.text = marker.title
        infoWindow.addressOfCenter.text = marker.snippet
        infoWindow.callNowButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

        return infoWindow
    }

and buttonTapped fuction is implemented as

@objc func buttonTapped(sender: UIButton) {
        print("Yeah! Button is tapped!")
    }

but the problem is that it is not going inside the function.

UPDATE

Based on the answer I started following this tutorial so this is what I've implemented:

First I have declared these two variables:

var tappedMarker = GMSMarker()
var infoWindow = emergencyInfo(frame: CGRect(x: 0, y: 0, width: 200, height: 100))

Then in didTap I did this: func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {

    let location = CLLocationCoordinate2D(latitude: marker.position.latitude, longitude: marker.position.longitude)

    tappedMarker = marker
    infoWindow.removeFromSuperview()
    infoWindow = emergencyInfo(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
    infoWindow.center = mapView.projection.point(for: location)
    infoWindow.callNowButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) //getting error on this line
    self.view.addSubview(infoWindow)

    return false
}

And finally I change the markerInfoWindow method to:

 func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
        return UIView()
}

Now when I run the code I get error on the line where I'm setting #selector(buttonTapped)

fatal error: unexpectedly found nil while unwrapping an Optional value

Based on some research I found that this error is occuring for the left hand side i.e. infoWindow.callNowButton because I have a label infoWindow.titleOfCenter.text for which I've just given "Title" at the moment and it crashes with the same error on it.

3

3 Answers

4
votes

Nikhil is correct. However, indeed there's a sweet workaround for this that requires a little bit of effort and changes.

Before we proceed to the workaround, read this answer https://stackoverflow.com/a/15281141/3231194:

Possibly, as mentioned officially in documentation of Google Maps Android API, the below restriction regarding infowindows applies to Google Maps iOS SDK also :

Info window is not a live View, rather the view is rendered as an image onto the map. As a result, any listeners you set on the view are disregarded and you cannot distinguish between click events on various parts of the view. You are advised not to place interactive components — such as buttons, checkboxes, or text inputs — within your custom info window.

So basically clicking on any part of the infowindow will trigger only "didTapWindowOfMarker"

Then for the workaround (I've done this already and it works), you can just follow this tutorial http://kevinxh.github.io/swift/custom-and-interactive-googlemaps-ios-sdk-infowindow.html which is easy.

Bottomline is: You will need to change how you're showing your infoWindow to the map. Instead of returning your custom infoWindow in markerInfoWindow, you will replace that with UIView().

Next is to handle the presentation (or showing) of your custom infoWindow in didTap marker, in there you will also handle set the selector, for example:

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
    guard let tappedJob = marker.userData as? Job else { return false }
    self.mapView.selectedMarker = marker

    jobInfoWindow?.buttons.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    jobInfoWindow?.job = tappedJob
    jobInfoWindow?.center = mapView.projection.point(for: marker.position)
    self.view.addSubview(jobInfoWindow!)

    return false
}
1
votes

GMSMarker gets rendered as images on maps, so we are unable to get callbacks of buttons or any other UI element.

A workaround could be using didTapWindowOfMarker.

You can also refer to this answer.

0
votes

So this is what I was doing wrong. I was not initializing the UIView Class with xib file. So I added:

 class func instanceFromNib() -> emergencyInfo {
        return UINib(nibName: "emergencyInfo", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! emergencyInfo
    }

and instead of infoWindow = emergencyInfo(frame: CGRect(x: 0, y: 0, width: 200, height: 100)) I added:

infoWindow = EmergencyViewController.instanceFromNib()

inside func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool { function.

And Glenn answer was also right up to some extent.