1

So I have been using Google Maps iOS SDK 4.0.0 and my requirement is like this when I tap on a marker it should add UIViewContoller's view which I easily achieved. Take a look on the following code:

var customeVC:CustomViewController?

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
    
    customeVC = CustomViewController(nibName: "CustomViewController", bundle: nil)
    customeVC?.delegate = self
    self.addChild(customeVC!)
    customeVC?.view.frame = self.view.frame
    self.view.addSubview(customeVC!.view)
    customeVC?.didMove(toParent: self)

    // Remember to return false
    // so marker event is still handled by delegate
    return false
}


func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
    
    //Empty the default infowindow
    return UIView()
}


extension MapViewController: CustomViewControllerDelegate {
    // Triggers when I close the full screen view of CustomViewController
    func didCloseWindow() {
        customeVC?.willMove(toParent: nil)
        customeVC?.removeFromParent()
        customeVC?.view.removeFromSuperview()
        customeVC = nil
    }
}

Now the main the problem is, after closing the window/view if I click on the same marker again (2nd time) its doesn't show the view. But if I click once again (3rd time), it shows.

So I'm suspecting after removing the view the marker doesn't get deselected. But when I tap for the 2nd time its gets deselected and tap for the 3rd time get selected again.

I have textfields & buttons inside CustomViewController thats why I didn't add this view inside the delegate function mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView?. Basically I followed this article which lets you click inside InfoWindow.

I also tried to mapView.selectedMarker = marker inside didTap delegate method and mapView.selectedMarker = nil when removing the view.

How do I deselect the marker so that each time I click on the same marker its should show the view?

Any help will be appreciated. Thanks in advance.

Poles
  • 3,585
  • 9
  • 43
  • 91

2 Answers2

2

After trying for several days finally I solved it. Basically tapping on marker works every time only if you draw only markers. But if you draw markers inside an overlay or a polygon then tapping on same marker for the 2nd time didn't work because 2nd time the following method of GMSMapViewDelegate gets fired.

func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay)

I didn't mention that, I was drawing markers inside an overlay because I never thought it can cause tapping issue. I found someone else also faced the issue earlier but his question was unanswered. So here is what I needed to update inside that delegate method to make it work and the rest code are the same.

I'm setting the isTappable polygon property to false when I'm tapping on a certain polygon and then I can play around with the markers which are drawn inside. Also I'm resetting the isTappable property to true of previously selected polygon as soon as user clicks on other polygon.

class ViewController: GMSMapViewDelegate {
    @IBOutlet weak var mapView:GMSMapView!
    private var selectedPolygon: GMSAptivePolygon?
    
    func mapView(_ mapView: GMSMapView, didTap overlay: GMSOverlay) {
        
        if let polygon = overlay as? GMSPolygon {
            
            // Make sure to restrict markers for a polygon if tapped more than once
            if selectedPolygon != polygon {
                
                // Reset polygon to tappable
                selectedPolygon?.isTappable = true
                
                // Fetch all annotations of this polygon if exits
                fetchMarkers(for: polygon)
                
                polygon.isTappable = false
                selectedPolygon = polygon
            }
        }
    }
}
Poles
  • 3,585
  • 9
  • 43
  • 91
1

I suspect your problem is more to do with how you are presenting and dismissing your CustomViewController because the didTap delegate method should be called regardless of state.

Initially I would add a test to check if tapping the marker is in-fact triggering the delegate method each time and move some of your presentation code in to a neater method outside of this delegate method e.g.

func showCustomView() {
    // make sure any previous CustomViewController are removed
    if let vc = self.customeVC {
        vc.willMove(toParent: nil)
        vc.removeFromParent()
        vc.view.removeFromSuperview()
        self.customeVC = nil
    }
    // initialise a new CustomViewController
    let cv = CustomViewController(
        nibName: "CustomViewController", 
        bundle: nil
    )
    cv.delegate = self
    self.addChild(cv)
    cv.view.frame = self.view.frame
    self.view.addSubview(cv.view)
    cv.didMove(toParent: self)
    self.customeVC = cv
}

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
    // print to check the marker is being tapped
    print("marker was tapped")
    // run presentation code
    showCustomView()
    // return true to prevent the map from
    // performing its default selection behaviour
    return true
}

I haven't tested this but I hope it helps you clear up the issue, let me know how you get on.


Another thing I would look in to is presenting the CustomViewController modally instead making use of modalPresentationStyle to show the custom view on top of the others without the need to add it as a subview as you are currently.

You'd need something like this in your CustomerViewControllers init

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    self.modalPresentationStyle = .overCurrentContext
    self.modalTransitionStyle = .crossDissolve
    self.modalPresentationCapturesStatusBarAppearance = true
}

Then you'd change your showCustomView() method to something like this

func showCustomView() {
    // make sure any previous CustomViewController are removed
    if let vc = self.customeVC {
        vc.dismiss(animated: true)
        self.customeVC = nil
    }
    // initialise a new CustomViewController
    let cv = CustomViewController(
        nibName: "CustomViewController", 
        bundle: nil
    )
    cv.delegate = self
    self.present(cv, animated: true, completion: nil)
    self.customeVC = cv
}

This would also assume that you have to dismiss the CustomViewController before you can interact with any other part of the map, a screenshot of what you are trying to achieve here might help anyone else to help you.

Wez
  • 10,555
  • 5
  • 49
  • 63
  • Thanks for the help. I tried with the same code both `addSubview` and `modalPresentationStyle` but `didTap` doesn't gets fired when I tap on the same marker after closing `CustomViewController`. – Poles Dec 03 '20 at 15:03
  • I just tested with my codebase and the `didTap` method is called every time i tap a marker (selected and unselected) - is it possible that the custom view is leaving something invisible that you tap? - I would comment out the bit where you add the `CustomViewController` and just try firing it with only the `print("tapped")` for testing. – Wez Dec 03 '20 at 15:39
  • I did that but the `didTap` method is not firing when I tap the same marker but if I tap other markers then its gets called. I don't have any other delegate methods except `didTap` just like yours. Here is a glimpse of that problem https://media.giphy.com/media/MzMZ1rZZFPU49d3wpV/giphy.gif – Poles Dec 03 '20 at 17:23
  • Have you tried `return nil` in your `markerInfoWindow ` delegate method? possibly the empty info window you are adding is causing issues? – Wez Dec 04 '20 at 09:35
  • Yes. I tried with returned nil as well as empty UiView but no luck. So in your cases you can click on same markers back to back and every time popviewcontroller shows? – Poles Dec 04 '20 at 13:16
  • Thats correct, my codebase uses a bottom sheet, and I can repeatedly tap the map marker and every time it will close and re-draw the bottom sheet. – Wez Dec 04 '20 at 16:55
  • Thats really strange ! What are the other things I should check? – Poles Dec 07 '20 at 16:39
  • 1
    You need to do some more debugging, start by commenting out and initialisation of the custom overlay, slowly removing things until you get to a point where tapping the marker works every time. then slowly re-introduce things until you find a point where it breaks, then debug from there. I would also make use of [Xcode's debug view hierarchy button](https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html) to inspect the ui after dismissing the custom overlay. – Wez Dec 07 '20 at 17:35
  • Finally I solved it and posted the answer. It was a unintended mistake. Thanks for your support. – Poles Jan 23 '21 at 09:28
  • Great news, glad you got there. – Wez Jan 23 '21 at 12:17