1

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.

Chaudhry Talha
  • 7,231
  • 11
  • 67
  • 116

3 Answers3

4

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
}
Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
  • Kindly see my updated questions I started implementing your answer but there is an error. – Chaudhry Talha Oct 10 '17 at 10:30
  • Can you clean up your question and just add the whole code of your view controller? :) That would be better. – Glenn Posadas Oct 10 '17 at 10:45
  • That would be a lot of code as I've a lot going on in this class. The `emergencyInfo` is a UIView class for which I've a `.xib` which I'm displaying as snippet when marker is tapped. This `.xib` has two buttons. The error is I think because the `UIView` is not yet loaded or something that is why it is saying nil. – Chaudhry Talha Oct 10 '17 at 10:53
  • Added a new finding in the last of my question which I found kindly see that too. – Chaudhry Talha Oct 10 '17 at 11:10
  • The answer is nicely put together. :) – Nikhil Manapure Oct 11 '17 at 06:18
1

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.

Nikhil Manapure
  • 3,748
  • 2
  • 30
  • 55
  • I added the method `didTapWindowOfMarker` and yes it works if I tap anywhere in the window. But if I had just one button that might've work for that, the issue is I've 2 buttons in in and both have a different method to run. – Chaudhry Talha Oct 10 '17 at 10:13
  • Sorry, but according to me, that will not be possible because we don't even get the location of the tap. – Nikhil Manapure Oct 10 '17 at 10:45
  • In my case, I had two actions, delete and edit. What I did is, I placed only edit button and then when user taps, I showed delete and edit in action sheet. – Nikhil Manapure Oct 10 '17 at 10:47
  • 1
    There is another workaround that I can think of. You can bring the marker to centre and show a pop up as an overlay by adding it above the `mapview` and therefore it will look like the marker has that popup. Now you are free to use as many buttons as you want. :) – Nikhil Manapure Oct 10 '17 at 10:51
  • 1
    Yes that would be the last option if nothing else works for me :) Thank you for your help. – Chaudhry Talha Oct 10 '17 at 10:52
0

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.

Chaudhry Talha
  • 7,231
  • 11
  • 67
  • 116
  • Salam @ChaudhryTalha my custominfomarker center point gone wrong position. i.e when i tap the marker the custominformarker not show correct position on top center on marker. If you any idea about it please share. – Anas Mehar Feb 19 '18 at 13:31