Entering UIButton and other UIControl objects inside MKAnnotationView and user interaction

I have my own annotation view on a map that has UIButton , but UIButton does not respond when clicked. I have two main problems with user interaction in the annotation view:

  • Buttons and other controls do not respond.
  • I want the annotation to block touches in accordance with my implementation - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event - that is, if I return YES, then I do not want the touches to be sent to MKMapView ( potentially choosing other annotations that BEHIND is my annotation look at), I want to handle this myself in this case.

I made sure that the userInteractionEnabled parameter userInteractionEnabled set to YES , and I examined how touches are sent to the user annotation view (my subclass of MKAnnotationView ) by overriding touchesBegan , etc., but it seems like the strokes are usually canceled (I think I managed to get touchesEnded several times) - so it seems that it will even be difficult to manually implement any interaction with the user view of the annotation.

Does anyone have an idea of โ€‹โ€‹the possibility of more interaction with MKAnnotationView objects?

+7
source share
4 answers

I managed to solve this with the help of a colleague. The solution is to override - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event . Our assumption is that MKAnnotationView (which should inherit your annotation view) overrides this to do the โ€œwrongโ€ thing (presumably so that the choice of annotation does not overlap between overlapping annotations). Therefore, you need to redefine it for proper operation and return the corresponding UIView , then the system will send events to it, and the user will be able to interact with it :). This has a useful (in this case) side effect that an interactive annotation blocks the selection of annotations that are behind it.

+5
source

I found that instead of overriding hitTest:withEvent: I could just override pointInside:withEvent: and just return it YES . I assume that officially I have to do the exact correction of the intersection to make sure that the place I click is inside the control, but in practice just put return YES seems to work fine, still allowing you to reject MKAnnotationView by clicking on it.

 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { // for testing purposes BOOL result = [super pointInside:point withEvent:event]; NSLog(@"pointInside:RESULT = %i", result); return YES; } 
0
source

Adding jhabbott's answer is what worked for me. I have a custom MKCustomAnnotationView annotation MKCustomAnnotationView that contains a CustomPin annotation as an annotation. This โ€œcontactโ€ contains UIButton as a replacement for the auxiliary button that I wanted to get by touch.

My hitTest method will look like this:

 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *result = [super hitTest:point withEvent:event]; //NSLog(@"ht: %f:%f %d %@", point.x, point.y, [[event touchesForView:self] count], result); if ([result isKindOfClass:[MKCustomAnnotationView class]]) { MKCustomAnnotationView *av = (MKCustomAnnotationView *)result; CustomPin *p = av.annotation; UIButton *ab = p.accessoryButton; if (p.calloutActive && point.x >= ab.frame.origin.x) return ab; } return result; } 

In most cases, a calloutActive bool is probably not required.

0
source

For those who want to add tapGesture to subview AnnotationView, then the answer is below:

MKannotationView with UIButton as a preview, button not responding

Worked for me:

 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (CGRectContainsPoint(_button.frame, point)) { return _button; } return [super hitTest:point withEvent:event]; } 
0
source

All Articles