Z-ordering of MKAnnotationViews
Asked Answered
C

3

15

I'm getting fairly frustrated with the limitations of MKMapKit. My current problem has to do with the z-ordering of annotation views, particularly as it relates to touches. If you accept the default z-order the mapkit gives you:

  1. The order appears random. The z-order is unrelated to the order the annotations were added.
  2. If one annotation ends up on top of another one, touching the top annotation generally brings up the callout for the bottom annotation. It seems like the hit detecting doesn't even respect the draw order. What's up with that?

I've tried solving #1 using something similar to the following code found on the web (which was designed to give some control over z-order)

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
   for (MKAnnotationView * annView in views) {
      TopBottomAnnotation * ann = (TopBottomAnnotation *) [annView annotation];
      if ([ann top]) {
         [[annView superview] bringSubviewToFront:annView];
      } else {
         [[annView superview] sendSubviewToBack:annView];
      }
   }

}

Running through the annotation views passed to mapView:didAddAnnotationViews: and adjusting their z-order does seem to fix #1. The problem is that now the callout views are no longer always on top to the annotation views. The MapKit seems to get very confused about the layers (callouts should be drawn in a layer above all annotation views). I can even figure out how it is getting confused since all the MKAnnotationViews you receive have the same superview (a private class MKOverlayView). You would think any reasonable design would draw the callouts about this overlay view.

Has anyone solved #1 or #2 successfully?

Clardy answered 5/11, 2009 at 16:4 Comment(3)
Where did you get the TopBottomAnnotation class?Samons
The TopBottomAnnotation is the name of your annotationview classTrifle
...nearly 6 years later and I am having the same issue. How has this not been fixed?Jankowski
H
8

If you have a custom annotationView (which sounds like you already have) you can try adding this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [self.superview bringSubviewToFront:self];
    [super touchesBegan:touches withEvent:event];
}

A side-effect is that each time a marker is touched it also pops to the front of the z-order, which actually is sensible since that's what the user is focusing on.

Hypotaxis answered 5/11, 2009 at 16:54 Comment(5)
Ramin, Thanks for responding. I don't think that quite solves my problem. It is the callouts that are not being displayed on top of the annotation views. I also need to control this z-order of the annotation views without the user having to touch them. Some of the views have higher "priority" and should be displayed on top of other lower priority views.Clardy
I don't know if it's the same problem but I had a bunch of marker pins placed close together. Tapping each pin would make the callouts show up underneath the other pins, so it looks like each annotationview maintains its own callout layer. But you're right, callouts should be on their own top layer. Might want to file a bugreport.Hypotaxis
Ramin, I just tried your solution, and it does indeed solve the problem of callouts not being displayed on top of all annotations. Thanks. There still seems to be an issue of which annotation gets the touch when they are overlapping. But that is less important than the other fix.Clardy
Ramin, thanks for this bit of code. I had a polyline route annotation that was goofing up location markers along the route... and this corrected the annotation touches that were being improperly handled - thanks!Gizzard
Sadly, this seems to fix iOS 3.x, but only semi-fix iOS 4.0-4.1: annotations pop to the fore now, but they don't always seem to be the one that was actually selected. Or maybe I'm doing it wrong. (Luckily, of course, Apple fixed finally fixed the bug properly in iOS 4.2.)Imprescriptible
S
7

Ramin, that is perfect for what I am trying to do. I did not have a custom annotation view defined though. I solved this by using a category and it worked perfect!

Here is the header:

#import <Foundation/Foundation.h> 
#import <MapKit/MapKit.h>


@interface MKPinAnnotationView (ZIndexFix)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; 
@end

And the Implementation:

#import "AEBMapViewCategory.h"
@implementation MKPinAnnotationView (ZIndexFix)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [self.superview bringSubviewToFront:self];
    [super touchesBegan:touches withEvent:event];
}
@end
Solnit answered 4/12, 2009 at 18:40 Comment(2)
how should this fit together with the mapViewForAnnotations or, more generally the rest of a mapview application? sorry it's not clear to me.Basilio
wow. so this kinda seems to 'just work'. which is pretty amazing, but I'd still like to know 'why'. and i have no idea.Basilio
T
6

Try another solution, setup annotation view layer's zPosition (annotationView.layer.zPosition) in:

(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views;

Temptation answered 3/5, 2013 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.