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

发布于 2024-11-30 20:33:20 字数 532 浏览 1 评论 0原文

我需要在所有其他注释之上绘制当前用户注释(蓝点)。现在它被绘制在我的其他注释下面并被隐藏。我想调整此注释视图(蓝点)的 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:????];
        }
    }
}

I need to draw the current user annotation (the blue dot) on top of all other annotations. Right now it is getting drawn underneath my other annotations and getting hidden. I'd like to adjust the z-index of this annotation view (the blue dot) and bring it to the top, does anyone know how?

Update:
So I can now get a handle on the MKUserLocationView, but how do I bring it forward?

- (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:????];
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

满栀 2024-12-07 20:33:20

感谢 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];
    }
  }
}

Finally got it to work using the code listed below thanks to the help from Paul Tiarks. The problem I ran into is that the MKUserLocation annotation gets added to the map first before any others, so when you add the other annotations their order appears to be random and would still end up on top of the MKUserLocation annotation. To fix this I had to move all the other annotations to the back as well as move the MKUserLocation annotation to the front.

- (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];
        }
    }
}

Update: You may want to add the code below to ensure the blue dot is drawn on top when scrolling it off the viewable area of the map.

- (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];
    }
  }
}
深海不蓝 2024-12-07 20:33:20

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

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

Another solution:
setup annotation view layer's zPosition (annotationView.layer.zPosition) in:

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

风渺 2024-12-07 20:33:20

iOS 14 更新

我知道这是一篇旧帖子,但问题仍然适用,当您将其输入到您最喜欢的搜索引擎时,您最终会到达这里。

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

来自 MKUserLocationView 的文档:

如果您想指定其他配置,例如zPriority,
直接创建这个注释视图。要显示注释视图,
mapView(_:viewFor:)< 返回实例/a>.


以下代码片段显示了如何完成此操作(将代码添加到您的 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 来完成的。

Update for iOS 14

I know it's an old post, but the question is still applicable and you end up here when typing it into your favorite search engine.

Starting with iOS 14, Apple introduced a zPriority property to MKAnnotationView. You can use it to set up the z-index for your annotations using predefined constants or floats.
Also, Apple made it possible to finally create the view for the user location on our own and provided MKUserLocationView as a subclass of MKAnnotationView.

From the documentation for MKUserLocationView:

If you want to specify additional configuration, such as zPriority,
create this annotation view directly. To display the annotation view,
return the instance from mapView(_:viewFor:).

The following code snippet shows how this can be done (add the code to your 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
}

Note that per default, the user location annotation shows a callout when tapping on it. Now that the user location overlays your other annotations, you'd probably want to disable this, which is done in the code by setting .isEnabled to false.

二智少女 2024-12-07 20:33:20

该线程的官方答案是错误的...使用 zPosition 确实是最好的方法,并且与使用 RegionDidChangeAnimated 相比是最快的...

否则您将因地图上的许多注释而遭受巨大的性能影响(因为帧的每次更改都会重新扫描所有注释)。并一直在测试它......

所以在创建注释视图时(或在 didAddAnnotationViews 中)设置:
self.layer.zPosition = -1; (低于所有其他)

并且正如 yuf 所指出的:
这使得图钉覆盖其他图钉的标注 – yuf 2013-12-05 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;
   ...
}

The official answer to that thread is wrong... using zPosition is indeed the best approach and fastest vs using regionDidChangeAnimated...

else you would suffer big performance impact with many annotations on map (as every change of frame would rescan all annotations). and been testing it...

so when creating the view of the annotation (or in didAddAnnotationViews) set :
self.layer.zPosition = -1; (below all others)

and as pointed out by yuf:
This makes the pin cover callouts from other pins – yuf Dec 5 '13 at 20:25

i.e. the annotation view will appear below other pins.

to fix, simply reput the zPosition to 0 when you have a selection

-(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;
   ...
}
救星 2024-12-07 20:33:20

只需使用 .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

Just use the .layer.anchorPointZ property.

Example:

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

Here is there reference https://developer.apple.com/documentation/quartzcore/calayer/1410796-anchorpointz

星光不落少年眉 2024-12-07 20:33:20

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

Try, getting a reference to the user location annotation (perhaps in mapView: didAddAnnotationViews:) and then bring that view to the front of the mapView after all of your annotations have been added.

留蓝 2024-12-07 20:33:20

斯威夫特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)
        }
 }

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)
        }
 }
成熟的代价 2024-12-07 20:33:20

这是一种使用谓词来完成此操作的方法。我认为应该更快

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];
}

Here is a way to do it using predicates. I think it should be faster

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];
}
感情废物 2024-12-07 20:33:20

使用下划线.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]]; });

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]]; });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文