MapKit (MKMapView): zPosition does not work anymore on iOS11

Viewed 3118

On iOS11 the zPosition stopped working for the annotationView.layer. Every time the map region changes.

enter image description here

  • No luck with original solution: layer.zPosition = X;
  • No luck with bringViewToFront/SendViewToBack methods

Xcode 8.3/9

UPDATE (SOLUTION thanks Elias Aalto):

When creating MKAnnotationView:

annotationView.layer.zPosition = 50;
if (IS_OS_11_OR_LATER) {
    annotationView.layer.name = @"50";
    [annotationView.layer addObserver:MeLikeSingleton forKeyPath:@"zPosition" options:0 context:NULL];

}

In MeLikeSingleton or whatever observer object you have there:

- (void)observeValueForKeyPath:(NSString *)keyPath
                         ofObject:(id)object
                           change:(NSDictionary *)change
                          context:(void *)context {

       if (IS_OS_11_OR_LATER) {

           if ([keyPath isEqualToString:@"zPosition"]) {
               CALayer *layer = object;
               int zPosition = FLT_MAX;
               if (layer.name) {
                   zPosition = layer.name.intValue;
               }
               layer.zPosition = zPosition;
               //DDLogInfo(@"Name:%@",layer.name);
           }

       } 
}
  • This solution uses the layer.name value to keep track of zOrder. In case you have many levels of zPosition (user location, cluster, pin, callout) ;)
  • No for loops, only KVO
  • I used a Singleton Object that observs the layer value changes. In case you have multiple MKMapViews used through out the app.

HOW IT WAS WORKING BEFORE IOS11

..is to use the

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

and set the zPosition here.

..but that (for some of us, still dunny why) does not work anymore in iOS11!

2 Answers

The zPosition does work, it's just that MKMapView overwrites it internally based on the somewhat broken and useless MKFeatureDisplayPriority. If you just need a handful of annotations to persist on top of "everything else", you can do this semi cleanly by using KVO. Just add an observer to the annotation view's layer's zPosition and overwrite it as MKMapView tries to fiddle with it.

(Please excuse my ObjC)

Add the observer:

        [self.annotationView.layer addObserver:self forKeyPath:@"zPosition" options:0 context:nil];

Overrule MKMapView

 - (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context
{
    if(object == self.annotationView.layer)
    {
        self.annotationView.layer.zPosition = FLT_MAX;
    }
}

Profit

Related