MKAnnotationView (s) Overlay Handling

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

I have a case where one address can have several annotations (on top of each other). For example, contact numbers 1, 2, 3, and 4 are located in the same geographical location. When the card loads, I want Pin # 1 to be on top, but there is no way to guarantee that Pin # 1 will always be visible (on top).

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

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

In my experience, this does not work! In my experience, adding annotations together with addAnnotations: or adding them one at a time leads to the same result. The order of presentation of annotations is still random.

 [self.mapView addAnnotations:allAnnotations]; 

It produces the same result as:

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

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

In my experience, this will not work! For example, the following code does not 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 indicate the exact order of all annotations.

Consider a scenario in which 4 contacts overlap, for example. Contact 1, 2, 3, and 4. The problem with this approach is that clicking on a particular annotation icon or selecting it programmatically does not bring it to the fore. zPosition is absolute. You can change it every time a contact is selected, but this is not ideal.

The zPosition property indicates the component of the z-axis of the position layer. The purpose of zPosition is to set the visual position of a layer relative to its related layers. This should not be used to indicate the order of siblings, instead reorders the layer in the sublayer array.

Thoughts?

+5
source share
2 answers

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.

+4
source

iOS 11 violated this solution (i.e. using zPosition ). To restore the ability to use zPosition , see This answer: fooobar.com/questions/190008 / ...

0
source

Source: https://habr.com/ru/post/1209911/


All Articles