To do this, you need to subclass MKAnnotationView to create your own MKAnnotationView . In your subclass, undo the following functions:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { // Return YES if the point is inside an area you want to be touchable } - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { // Return the deepest view that the point is inside of. }
This allows the use of interactive presentations (e.g. buttons, etc.). The default implementation in MKAnnotationView not strict on pointInside and hitTest , because it allows clicks that are actually inside one annotation to send them to another annotation. He does this by calculating the closest center of annotations to the touch point and sending events to this annotation, so that the close (overlapping) annotations do not block each other from choosing. However, in your case, you probably want to block other annotations if the user needs to select and drag the topmost annotation, so the above method is probably what you want, otherwise it will set you on the right path.
EDIT: I asked in the comments for an example implementation of hitTest:withEvent: It depends on what you are trying to achieve. The initial question suggested touching and dragging the images in the annotation, whereas in my case I have some buttons inside the annotation that I want to be interactive. Here is my code:
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { UIView* hitView = [super hitTest:point withEvent:event]; if (hitView != nil) { // ensure that the callout appears above all other views [self.superview bringSubviewToFront:self]; // we tapped inside the callout if (CGRectContainsPoint(self.resultView.callButton.frame, point)) { hitView = self.resultView.callButton; } else if (CGRectContainsPoint(self.resultView.addButton.frame, point)) { hitView = self.resultView.addButton; } else { hitView = self.resultView.viewDetailsButton; } [self preventSelectionChange]; } return hitView; }
As you can see, this is pretty simple. The MKAnnotationView implementation (called super on the first line of my implementation) returns only the first (external) view, it does not flow through the view hierarchy to see which subview is actually inside. In my case, I just check if the touch press of one of the three buttons is located and returns them. In other cases, you may have simple rectangle-based drilling through a hierarchy or more complex impact tests, for example, to avoid transparent areas in your view, to allow touches to go through these parts. If you need to expand, CGRectContainsPoint can be used in the same way as I used it, but do not forget to compensate for your points in the local coordinates of the view for each viewing level in which you train.
The preventSelectionChange method is to prevent my custom annotation from being selected, I use it as a custom / interactive callout from the map pins, and this connects it to the selected one, and does not allow the selection to change this annotation.