iOS MapKit用户位置标注的Z-index



我需要将当前用户注释(蓝点)绘制在所有其他注释的顶部。现在它被画在其他注解的下面,然后被隐藏起来。我想调整这个注释视图的z-index(蓝点)把它放到最上面,有人知道怎么做吗?

更新:我现在可以获得MKUserLocationView的句柄,但我如何把它向前推进呢?

- (void) mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views {
    for (MKAnnotationView *view in views) {
        if ([[view annotation] isKindOfClass:[MKUserLocation class]]) {
            // How do I bring this view to the front of all other annotations?
            // [???? bringSubviewToFront:????];
        }
    }
}

在Paul Tiarks的帮助下,使用下面列出的代码最终使其工作。我遇到的问题是,MKUserLocation注释在其他注释之前首先被添加到地图中,所以当您添加其他注释时,它们的顺序似乎是随机的,并且仍然会在MKUserLocation注释的顶部结束。为了解决这个问题,我必须将所有其他注释移动到后面,以及将MKUserLocation注释移动到前面。

- (void) mapView:(MKMapView *)aMapView didAddAnnotationViews:(NSArray *)views 
{
    for (MKAnnotationView *view in views) 
    {
        if ([[view annotation] isKindOfClass:[MKUserLocation class]]) 
        {
            [[view superview] bringSubviewToFront:view];
        } 
        else 
        {
            [[view superview] sendSubviewToBack:view];
        }
    }
}

更新:您可能需要添加下面的代码,以确保当将蓝点滚动到地图的可视区域时,它绘制在顶部。

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{        
  for (NSObject *annotation in [mapView annotations]) 
  {
    if ([annotation isKindOfClass:[MKUserLocation class]]) 
    {
      NSLog(@"Bring blue location dot to front");
      MKAnnotationView *view = [mapView viewForAnnotation:(MKUserLocation *)annotation];
      [[view superview] bringSubviewToFront:view];
    }
  }
}

另一个解决方案:设置注释视图层的zPosition (annotationView.layer.zPosition) in:

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

这个帖子的官方答案是错误的…使用zPosition确实是最好的方法和最快的使用regionDidChangeAnimated…

否则,map上的许多注释将对性能造成很大影响(因为每次更改帧都会重新扫描所有注释)。我一直在测试它……

所以当创建注释的视图(或在didAddAnnotationViews)集时:self.layer.zPosition = -1;

,正如你所指出的:这使得引脚盖标注从其他引脚- yuf Dec 5 '13 at 20:25

。注释视图将出现在其他引脚的下方。

要修复

,只需在有选择

时将zPosition重新设置为0即可。
-(void) mapView:(MKMapView*)mapView didSelectAnnotationView:(MKAnnotationView*)view {
    if ([view isKindOfClass:[MyCustomAnnotationView class]])
        view.layer.zPosition = 0;
   ...
}
-(void) mapView:(MKMapView*)mapView didDeselectAnnotationView:(MKAnnotationView*)view {
    if ([view isKindOfClass:[MyCustomAnnotationView class]])
        view.layer.zPosition = -1;
   ...
}

iOS 14更新

我知道这是一个老帖子,但是这个问题仍然适用,当你在你最喜欢的搜索引擎中输入它时,你会在这里结束。

从iOS 14开始,Apple为MKAnnotationView引入了zPriority属性。您可以使用它为使用预定义常量或浮点数的注释设置z-index。此外,Apple最终使我们能够自己创建用户位置视图,并提供MKUserLocationView作为MKAnnotationView的子类。

来自MKUserLocationView的文档:

如果您想指定额外的配置,如zPriority,直接创建这个注释视图。要显示注释视图,返回mapView(_:viewFor:)的实例

下面的代码片段显示了如何做到这一点(将代码添加到MKMapViewDelegate中):

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    
    // Alter the MKUserLocationView (iOS 14+)
    if #available(iOS 14.0, *), annotation is MKUserLocation {
        
        // Try to reuse the existing view that we create below
        let reuseIdentifier = "userLocation"
        if let existingView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier) {
            return existingView
        }
        let view = MKUserLocationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
        
        view.zPriority = .max   // Show user location above other annotations
        view.isEnabled = false  // Ignore touch events and do not show callout
        
        return view
    }
    
    // Create views for other annotations or return nil to use the default representation
    
    return nil
}

注意,默认情况下,用户位置注释在点击它时会显示一个标注。现在用户位置覆盖了其他注释,您可能想要禁用它,这可以在代码中通过将.isEnabled设置为false来实现。

使用.layer.anchorPointZ属性。

的例子:

 func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
        views.forEach {
            if let _ = $0.annotation as? MKUserLocation {
                $0.layer.anchorPointZ = 0
            } else {
                $0.layer.anchorPointZ = 1
            }
        }
    }

这里有参考https://developer.apple.com/documentation/quartzcore/calayer/1410796-anchorpointz

尝试,获得对用户位置注释的引用(可能在mapView: didAddAnnotationViews:中),然后在添加所有注释后将该视图带到mapView的前面。

Swift 3:

internal func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
        for annotationView in views {
            if annotationView.annotation is MKUserLocation {
                annotationView.bringSubview(toFront: view)
                return
            }
            annotationView.sendSubview(toBack: view)
        }
 }

这里有一种使用谓词的方法。我觉得应该快一点

NSPredicate *userLocationPredicate = [NSPredicate predicateWithFormat:@"class == %@", [MKUserLocation class]];
NSArray* userLocation = [[self.mapView annotations] filteredArrayUsingPredicate:userLocationPredicate];
if([userLocation count]) {
    NSLog(@"Bring blue location dot to front");
    MKAnnotationView *view = [self.mapView viewForAnnotation:(MKUserLocation *)[userLocation objectAtIndex:0]];
    [[view superview] bringSubviewToFront:view];
}

Using Underscore.m

_.array(mapView.annotations).
    filter(^ BOOL (id<MKAnnotation> annotation) { return [annotation 
isKindOfClass:[MKUserLocation class]]; })
    .each(^ (id<MKAnnotation> annotation) { [[[mapView 
viewForAnnotation:annotation] superview] bringSubviewToFront:[mapView 
viewForAnnotation:annotation]]; });

最新更新