Warning! The accepted solution and also the one below is sometimes bit buggy. Why? Sometimes you tap annotation but your code will act like if you tapped the map. What is the reason of this? Because you tapped somewhere around your frame of your annotation, like +- 1-6 pixels around but not within frame of annotation view.
Interesting also is, that while your code will say in such case "you tapped map, not annotation" default code logic on MKMapView will also accept this close tap, like if it was in the annotation region and will fire didSelectAnnotation.
So you have to reflect this issue also in your code.
Lets say this is the default code:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
CGPoint p = [gestureRecognizer locationInView:_customMapView];
UIView *v = [_customMapView hitTest:p withEvent:nil];
if (![v isKindOfClass:[MKAnnotationView class]])
{
return YES; // annotation was not tapped, let the recognizer method fire
}
return NO;
}
And this code takes in consideration also some proximity touches around annotations (because as said, MKMapView also accepts the proximity touches, not only correct touches):
I included the Log functions so you can watch it in console and understand the problem.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
CGPoint p = [gestureRecognizer locationInView:_customMapView];
NSLog(@"point %@", NSStringFromCGPoint(p));
UIView *v = [_customMapView hitTest:p withEvent:nil];
if (![v isKindOfClass:[MKAnnotationView class]])
{
// annotation was not tapped, be we will accept also some
// proximity touches around the annotations rects
for (id<MKAnnotation>annotation in _customMapView.annotations)
{
MKAnnotationView* anView = [_customMapView viewForAnnotation: annotation];
double dist = hypot((anView.frame.origin.x-p.x), (anView.frame.origin.y-p.y)); // compute distance of two points
NSLog(@"%@ %f %@", NSStringFromCGRect(anView.frame), dist, [annotation title]);
if (dist <= 30) return NO; // it was close to some annotation se we believe annotation was tapped
}
return YES;
}
return NO;
}
My annotation frame has 25x25 size, that's why I accept distance of 30. You can apply your logic like if (p.x >= anView.frame.origin.x - 6) && Y etc..
MKAnnotationContainerView
is though. I was expecting theUIView *v
hitTest to be a MKMapView and was surprised that it isn't. Thank you very much for your help, I really appreciate it. Out of curiosity, do you use xCode? I am unfamiliar with the second method header. – Papeete