Handling overlapping MKAnnotationView(s)
Asked Answered
S

2

7

How can we ensure that the annotation views are placed in a specified order/ position on the map?

I have a case where a single address can have multiple annotations (on top of each other). For example, Pin numbers 1, 2, 3, and 4 are placed at the same geo-location. When the map loads, I want Pin # 1 to be on the top, but there's no way to ensure that Pin # 1 will always be visible (on the top).

Looking around I found the following solutions, but none of these have worked for me.

1). Add the annotations to the map, in the order you want it.

In my experience, it doesn't work! In my experience, adding annotations together using addAnnotations: or adding them one by one generates the same result. The order of annotation views are still random.

[self.mapView addAnnotations:allAnnotations];

Generates the same result as:

for (MyCustomAnnotation *annotation in allAnnotations) {
    [self.mapView addAnnotation:annotation];
}

2). Use bringSubviewToFront or sendSubviewToBack to specify the order of all annotations.

In my experience it doesn't work! For example, the following code doesn't generate the required results:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    // .tag associated with each view specifies the order/hierarchy of annotation views
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"tag" ascending:YES];
    NSArray *orderedAnnotationViews = [views sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    for (MKAnnotationView *annotationView in orderedAnnotationViews) {
        [mapView sendSubviewToBack:annotationView];
    }
}

3). Use annotationView.layer.zPosition to specify the exact order of all annotations.

Consider a scenario where 4 pins are overlapping e.g. Pin 1, 2, 3, and 4. The problem with this approach is that tapping on a specific annotation pin or programmatically selecting it doesn't bring it to the front. The zPosition is absolute. You can change it every time a pin is selected, but that's not ideal.

The zPosition property specifies the z-axis component of the layer's position. The zPosition is intended to be used to set the visual position of the layer relative to its sibling layers. It should not be used to specify the order of layer siblings, instead reorder the layer in the sublayer array.

Thoughts?

Sympathizer answered 26/12, 2014 at 10:49 Comment(1)
Order of annotation is change when you tap on them. I mean for each tap on group of annotation, map will show annotation which is not on the top. Yes order of annotation is not fix. Good point for an experiment here.Dusa
S
4

I ended up working with zPosition:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"tag" ascending:NO];
    NSArray *sortedViews = [views sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    // Set zPosition
    for (MKAnnotationView *annotationView in sortedViews) {
        annotationView.layer.zPosition = ++_zPositionForAnnotationViews;
    }

    // Do whatever
    // . . .
}

- (void)mapView:(MKMapView *)aMapView didSelectAnnotationView:(MKAnnotationView *)view {
    NSLog(@"The annotation tapped is: %@", view.annotation.title);

    // Ignore tap on user location
    if ([view.annotation isKindOfClass:[MKUserLocation class]]) {
        return;
    }

    // Update zPosition (to bring it to front)
    view.layer.zPosition = ++_zPositionForAnnotationViews;

    // Do whatever
    // . . .
}

Where _zPositionForAnnotationViews is a class variable.

Sympathizer answered 1/1, 2015 at 4:41 Comment(1)
Why just not to set some big number for annotationView.layer.zPosition in didAddAnnotationViews:? And not to iterate trow all views?Adames
S
0

iOS 11 broke the given solution here (ie. using zPosition). To restore the ability to use zPosition see this answer: https://mcmap.net/q/395844/-how-to-define-the-order-of-overlapping-mkannotationviews

Stanza answered 25/1, 2018 at 23:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.