Mkannotationview and Tap Detection

Detect Tap on CalloutBubble in MKAnnotationView

Could you add a gesture recognizer when you're initializing the MKAnnotationView?

Here's the code for inside dequeueReusableAnnotationViewWithIdentifier:

UITapGestureRecognizer *tapGesture = 
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(calloutTapped:)];
[theAnnotationView addGestureRecognizer:tapGesture];
[tapGesture release];

The method for the gesture recognizer:

-(void) calloutTapped:(id) sender { 
// code to display whatever is required next.

// To get the annotation associated with the callout that caused this event:
// id<MKAnnotation> annotation = ((MKAnnotationView*)sender.view).annotation;
}

MKAnnotationView and tap detection

There might be a better and cleaner solution but one way to do the trick is exploiting hitTest:withEvent: in the tap gesture recognized selector, e.g.

suppose you have added a tap gesture recognizer to your _mapView

- (void)tapped:(UITapGestureRecognizer *)g
{
CGPoint p = [g locationInView:_mapView];
UIView *v = [_mapView hitTest:p withEvent:nil];

if (v == subviewOfKindOfClass(_mapView, @"MKAnnotationContainerView"))
NSLog(@"tap on the map"); //put your action here
}

// depth-first search
UIView *subviewOfKindOfClass(UIView *view, NSString *className)
{
static UIView *resultView = nil;

if ([view isKindOfClass:NSClassFromString(className)])
return view;

for (UIView *subv in [view subviews]) {
if ((resultView = subviewOfKindOfClass(subv, className)) break;
}
return resultView;
}

It's probably doesn't cover all the edge cases but it seems to work pretty well for me.

UPDATE (iOS >= 6.0)

Finally, I found another kind of solution which has the drawback of being valid only for iOS >= 6.0: In fact, this solution exploits the new -(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer added to the UIViews in this way

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// overrides the default value (YES) to have gestureRecognizer ignore the view
return NO;
}

I.e., from the iOS 6 onward, it's sufficient to override that UIView method in each view the gesture recognizer should ignore.

How to detect taps on MKMapView but ignore taps on MKAnnotationViews

Finally worked it out for myself. The trick was to use the UIGestureRecognizerDelegate to intercept the tap and decide whether or not the UITapGestureRecognizer should handle it.

The following delegate method code checks what has been tapped on, and ignores it if it's an MKPinAnnotationView:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
{
if (touch.view.self?.isKind(of: MKPinAnnotationView.self) == true)
{
return false
}
return true
}

Tapping an MKAnnotation to select it is REALLY slow

Unfortunately, there's nothing you can do about this. It's for the exact same reason that tapping links in Mobile Safari is slow: the gesture recognizers have to jostle for a while to decide whether you might be scrolling (dragging) before they agree that you are tapping.

So, it has nothing to do with the animation. It's just the nature of gesture recognition in this situation.

Prevent touch events on MKMapView being detected when a MKAnnotation is tapped

I think you will find the following links very useful:

http://blog.asynchrony.com/2010/09/building-custom-map-annotation-callouts-part-2/

How do I make a MKAnnotationView touch sensitive?

The first link discusses (among other things) how to prevent the propagation of touches to the annotations so that they selectively respond, and the second one how to detect the touches.

Detecting the tap which changes the selected annotation or deselects it

There is a delegate method for this. Just make sure you set the delegate property of the map view to the containing view controller.

optional func mapView(_ mapView: MKMapView, didDeselect view: 
MKAnnotationView)

This link may help you: https://developer.apple.com/documentation/mapkit/mkmapviewdelegate

Detect on calloutAccessoryControlTapped only the tap on rightCalloutAccessoryView

To achieve it you would need to add target for the right accessory view. You can achieve it by setting button to rightCalloutAccessoryView as shown in the code snippet.

class MapViewController: UIViewController, MKMapViewDelegate {

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is Annotation {
let annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "reuseIdentifier")
let rightButton = UIButton(type: .DetailDisclosure)
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(_:)), forControlEvents: .TouchUpInside)
annotationView.rightCalloutAccessoryView = rightButton
}
return nil
}

func didClickDetailDisclosure(button: UIButton) {
// TODO: Perform action when was clicked on right callout accessory view.
}
}

// Helper classes.
class Annotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?

init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}

class AnnotationView: MKAnnotationView {

}


Related Topics



Leave a reply



Submit