How can I catch tap on MapView and then pass it to default gesture recognizers?
Asked Answered
B

2

11

Here is what I want - user taps on the map, my code gets executed and then system code is executed (if user clicked on annotation callout is presented etc...).

I added simple tap recognizer to map view:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(mapViewTapped:)];
[self.mapView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];

Inside mapViewTapped my code gets executed. Now I want to notify system code of tap (for example to show callout). How do I do that? How to pass event that I intercepted?

Buss answered 14/3, 2012 at 10:47 Comment(0)
G
24

One way is to implement the UIGestureRecognizerDelegate method gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: and return YES in it:

//add <UIGestureRecognizerDelegate> to .h to avoid compiler warning

//add this where you create tapGestureRecognizer...
tapGestureRecognizer.delegate = self;

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
    shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

Now your mapViewTapped: will get called and then the map view's recognizer will call its method. If the tap was on an annotation view, the map view will show its callout (and the didSelectAnnotationView delegate method will get called if you've implemented it).


Another way, if you need more control, then instead of doing the above, in your mapViewTapped: you can check if the tap was on an annotation view and then manually select the annotation which will then show its callout (and call the didSelectAnnotationView delegate method):

-(void)mapViewTapped:(UITapGestureRecognizer *)tgr
{
    CGPoint p = [tgr locationInView:mapView];

    UIView *v = [mapView hitTest:p withEvent:nil];

    id<MKAnnotation> ann = nil;

    if ([v isKindOfClass:[MKAnnotationView class]])
    {
        //annotation view was tapped, select it...
        ann = ((MKAnnotationView *)v).annotation;
        [mapView selectAnnotation:ann animated:YES];
    }
    else
    {
        //annotation view was not tapped, deselect if some ann is selected...
        if (mapView.selectedAnnotations.count != 0)
        {
            ann = [mapView.selectedAnnotations objectAtIndex:0];
            [mapView deselectAnnotation:ann animated:YES];
        }
    }
}
Gripping answered 14/3, 2012 at 13:13 Comment(3)
Thank you, your explanation was not only useful, but very detailedBuss
Many thanks, your second suggestion was exactly what I was after!Pinole
That is a perfect solutionEdible
P
0

Second option for Swift enjoyers:

@objc private func mapViewTapped(sender: UITapGestureRecognizer) {
    let point = sender.location(in: mapView)
    if let view = mapView.hitTest(point, with: nil) as? MKAnnotationView {
        if let annotation = view.annotation {
            mapView.selectAnnotation(annotation, animated: true)
        }
    } else {
        let selected = mapView.selectedAnnotations
        if selected.count != 0 {
            mapView.deselectAnnotation(selected[0], animated: true)
        }
    }
}
Pastiness answered 9/7, 2021 at 17:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.