Detecting touches on MKOverlayView

So you’ve used MKOverlayView to add a Google Map to your app and you’ve added to it a series of MKOverlays and implemented mapView:viewForOverlay: which returns the corresponding MKOverlayView for your overlay. But the problem is that now you want to detect touch events on the MKOverlayView so that an action can be taken depending on which view is tapped.

This seems to be one of those questions that many have asked, but has not really received any successful answer! Well, there is actually a way to detect touches on an MKOverlayView, and it’s surprisingly simple!

The first thing you need to do is set up an NSMutableArray as an ivar to store all MKOverlayViews currently visible on the screen. The simplest thing to do here would be would be to to just store every MKOverlayView you create in mapView:viewForOverlay: in this array. The problem is that if you keep adding (and never removing) overlays as the map moves, your array will keep growing and growing which may cause performance issues in what comes later.

So now you have an ivar (let’s call it overlayViews) which contains all the MKOverlayViews currently visible on the map (it may also contain other MKOverlayViews that are no longer visible if you go with the simple approach).

Next thing you need to do is create a UIGestureRecognizer and add it to the MKMapView (which I assume is called mapView). You can do this in viewDidLoad. Simply add the following three lines:

    UIGestureRecognizer *gestureRecognizer = [[GestureRecognizer alloc] init];
    gestureRecognizer.delegate = self;
    [mapView addGestureRecognizer:gestureRecognizer];

UIGestureRecognizer is a class used to handle touch gestures, and by setting the delegate to self and adding it as a gesture recogniser to the MKMapView, which means that all touch events will now fire a delegate method on self.

This would be a good time to modify your header file to implement UIGestureRecognizerDelegate. While you’re there, declare a new ivar called dragging of type BOOL – we’ll explain why in a moment. Back in your main file, you can now implement the UIGestureRecognizerDelegate methods:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  {
    dragging = NO;

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    dragging = YES;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (!dragging) {
        if ([touches count] == 1) {
            UITouch *touch = [touches anyObject];
            for (MKOverlayView *overlayView in overlayViews) { // this is where things can get inefficient if you have loads of overlayViews that aren't even visible!
                CGSize overlayViewSize = overlayView.frame.size;

                CGPoint touchPoint = [touch locationInView:overlayView];

                if (touchPoint.x > 0 && touchPoint.x < overlayViewSize.width && touchPoint.y > 0 && touchPoint.y < overlayViewSize.height) {
                    [self overlayTouched:overlayView]; // overlayView is the one that was touched!

Let’s go through this step-by-step. Firstly, why did we need the dragging BOOL? Well, not only do you want to be able to handle touch events for the MKOverlayView, you also will likely want to still allow the user to scroll and pinch-zoom on the map. If you simply directed all touch events to the MKOverlayView, you would end up with a situation that even touching and dragging at a point on the map over an MKOverlayView would result in a touch event being triggered on the MKOverlayView, which is probably not what you wanted. Therefore, the dragging boolean keeps track of whether the user is dragging their finger across the screen, and if so, the touch event is ignored and is just handled by the MKMapView. That’s why in touchesBegin:withEvent: we set dragging = NO, and when touchesMoved:withEvent: we update dragging = YES. If touchesBegin:withEvent: is followed immediately by touchesEnded:withEvent: then dragging remains NO and we know that it was a tap, rather than a drag.

So once we know that the touch event is indeed a tap and not a drag, we then iterate over all of the MKOverlayViews that we stored previously in overlayViews, and for each one we compare the coordinates of the touch event against the coordinates of the overlayView. If the touch event lies within the frame of the overlayView then we know that that is the MKOverlayView that was touched, and can take action appropriately.

That action could be handled in the class itself, or you might choose to subclass MKOverlayView so that the view can handle its own events, and then call a method on it (e.g. [overlayView touched]) where appropriate.

56 Responses to “Detecting touches on MKOverlayView”

  1. Sang says:

    In fact when someone doesn’t understand after that its up to other users that
    they will help, so here it happens.

    Visit my web site – dayz free download (Sang)

  2. Stephany says:

    I pay a quick visit each day a few sites and blogs to read articles, except this web site offewrs quality based posts.

    My site Talent

  3. Jayson says:

    Just want to say your article is as amazing. The clearness on your submit is
    just great and that i can suppose you’re knowledgeable in this subject.
    Well together with your permission let me to snatch your feed
    to stay updated with impending post. Thanks one million and please keep
    up the gratifying work.

    Visit my web-site … cursos gratis de tarot

  4. Stanley says:

    Hey I know this is off topic but I was wondering if you knew of any widgets I
    could add to my blog that automatically tweet my
    newest twitter updates. I’ve been looking for a plug-in like this
    for quite some time and was hoping maybe you would
    have some experience with something like this.
    Please let me know if you run into anything. I truly enjoy
    reading your blog and I look forward to your new updates.

    Stop by my website: marketing online

  5. Louann says:

    Hey There. I found youjr blog the use of msn. That is a very
    well written article. I’ll be sure to bookmark it
    and return to learn extra of your useful information. Thabk you for the
    post. I will certainly comeback.

    Here is my homepage; phaseolus vulgaris information

  6. Cindi says:

    For most recent information you have to visit world wide web and on internet I found this
    site as a most excellent web page for hottest updates.

    Here is my web-site: affiliate website builder

Leave a Reply