views:

589

answers:

3

In my iphone application, I'm using MapKit with MKMapView and custom MKAnnotationView.

The problem is when annotations overlap on map (in my app, annotations are photos and those photos may overlap) and when you tap on the annotation that appears on front, it's another annotation (on back) which receives the event (seems to be random).

I didn't find any way to send the event to the front annotation. I cannot believe this bug/problem doesn't have any solution!

Z ordering and Order of overlapping annotations questions on stackoverflow did not help me that much.

Please any idea is welcome (even dirty solutions)!

Here's some of my code (nothing fancy, very common):

CustomAnnotation.h

@interface CustomAnnotation : NSObject <MKAnnotation> {
   @private
   CustomAnnotationView* view;
}

    @property (nonatomic, retain) CustomAnnotationView* view;

@end

CustomAnnotation.m

@implementation CustomAnnotation

@synthetize view;

CustomAnnotationView.h

@interface CustomAnnotationView : MKAnnotationView {
}

@end

CustomAnnotationView.m

@implementation CustomAnnotationView

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
// Do something related to the annotation tapped
}

@end

Main class ... // Annotations are added and some of them overlaps with others.

- (void)addAnnotation:(CustomAnnotation*)annotation {
    [map addAnnotation:annotation];
}

...

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {

    NSString* identifier = getIdentifierFromAnnotation(annotation);
    CustomAnnotationView* view;
    if(!(view = (CustomAnnotationView*)[map dequeueReusableAnnotationViewWithIdentifier:identifier])) {
        view = [[CustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier: identifier];
        [(CustomAnnotation*)annotation setView:view];
        [view release];
    }
    return view;
}
A: 

See the solution to this question. Basically you'll create a transparent UIView which will intercept all of the touches. I haven't tried it, but this may be more trouble than it's worth if you have to reimplement all of the pinch-to-zoom functionality in MKMapView.

If you have two (or more) MKAnnotations co-located you can repeatedly tap to toggle between the two. That should work without any changes to your app.

smountcastle
+1  A: 

Finally, the best way I found and that avoids loosing map funcionalities is to:

  • let the touch listener on CustomAnnotationView (touchesEnded) (on each annotation)

  • when receiving touch event, transfer the event to main class

  • main class loops on annotations and keeps the annotation that has a good location (touch event in the annotation frame) and that is in front

It works pretty well.

Alexandre Gellibert
Great idea. I did the transparent UIView and found it lacking.
rik.the.vik
I'd love to know how you're dealing with the 3rd bullet point. How do you find the frontmost annotation at a certain CGPoint or CGRect?
Sam V
A: 

Following up on Alexandre's answer, I disabled all my custom MKAnnotationViews objects with

annView.enabled = NO

so they don't respond to the MKMapView default select behavior, and implemented in my custom MKAnnotationView the following:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    self.enabled = YES;
    [(MKMapView*)self.superview selectAnnotation:self.annotation animated:NO];
}

This solution works great on iOS 4. It seems like disabling an MKAnnotationView doesn't disable its userInteractionEnabled, whereas on iOS 3 it does. Still looking for a solution for iOS 3...

Sam V