39

我的地图中有几个 MKAnnotations(及其对应的视图),有时它会变得非常拥挤。现在,我的应用程序中的注释有两种形式:一些肯定会留在原地,而另一些会随着时间的推移而移动。我更喜欢在背景中视觉上更稳定的那些,而移动的总是在他们面前经过。

也许有人会认为,最近添加到地图的注释最终会出现在前面(或者至少在最后面),但这似乎不是规则。据我所知,我首先创建并添加了所有非移动注释,然后添加了一些新实例化的移动注释,但其中许多(尽管不是全部!)最终绘制在永久静止的注释下。

有趣的是,随着时间的流逝,当新的移动注释被创建时,它们往往比第一个注释更多地被吸引到顶部——即使所有移动注释对象都是在非移动部分已添加到地图后才创建的。

有谁知道改变地图上注释视图这种奇怪的自然顺序的技巧?我试图搜索 Map Kit API,但它似乎没有说这样的事情。

4

7 回答 7

40

好的,所以对于来自 MKMapViewDelegate 的解决方案使用方法


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

在这种方法中,您应该在将 AnnotationView 添加到 mapKit 视图后重新排列它。因此,代码可能如下所示:


- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
   for (MKAnnotationView * annView in views) {
      TopBottomAnnotation * ann = (TopBottomAnnotation *) [annView annotation];
      if ([ann top]) {
         [[annView superview] bringSubviewToFront:annView];
      } else {
         [[annView superview] sendSubviewToBack:annView];
      }
   }

}

这对我有用。

于 2009-07-31T16:09:00.423 回答
28

在 iOS 11 下,实现displayPriority打破了所有使用bringSubviewToFrontzPosition.

如果您覆盖注释视图的 CALayer,您可以从操作系统中夺回对 zPosition 的控制权。

class AnnotationView: MKAnnotationView {

    /// Override the layer factory for this class to return a custom CALayer class
    override class var layerClass: AnyClass {
        return ZPositionableLayer.self
    }

    /// convenience accessor for setting zPosition
    var stickyZPosition: CGFloat {
        get {
            return (self.layer as! ZPositionableLayer).stickyZPosition
        }
        set {
            (self.layer as! ZPositionableLayer).stickyZPosition = newValue
        }
    }

    /// force the pin to the front of the z-ordering in the map view
   func bringViewToFront() {
        superview?.bringSubviewToFront(toFront: self)
        stickyZPosition = CGFloat(1)
    }

    /// force the pin to the back of the z-ordering in the map view
   func setViewToDefaultZOrder() {
        stickyZPosition = CGFloat(0)
    }

}

/// iOS 11 automagically manages the CALayer zPosition, which breaks manual z-ordering.
/// This subclass just throws away any values which the OS sets for zPosition, and provides
/// a specialized accessor for setting the zPosition
private class ZPositionableLayer: CALayer {

    /// no-op accessor for setting the zPosition
    override var zPosition: CGFloat {
        get {
            return super.zPosition
        }
        set {
            // do nothing
        }
    }

    /// specialized accessor for setting the zPosition
    var stickyZPosition: CGFloat {
        get {
            return super.zPosition
        }
        set {
            super.zPosition = newValue
        }
    }
}
于 2018-01-25T23:23:07.983 回答
11

尝试在以下位置设置注释视图层的 zPosition (annotationView.layer.zPosition):

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views;
于 2013-05-03T10:40:20.620 回答
5

斯威夫特 3:

我从 API 获取引脚位置,我遇到了类似的问题,必须在顶部的引脚没有。我能够像这样解决它。

var count = 0 // just so we don't get the same index in bottom pins
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {  
    for view in views {
        view.layer.zPosition = CGFloat(count)
    }
    count += 1
    if count > 500 {
        count = 250 // just so we don't end up with 999999999999+ as a value for count, plus I have at least 30 pins that show at the same time and need to have lower Z-Index values than the top pins. 
    }

}

希望这可以帮助

于 2016-12-05T21:06:56.770 回答
4

在委托功能中,您可以选择引脚以将其强制置于顶部:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?` {
    ...
    if my annotation is the special one {
        annotationView.isSelected = true
    }
    ...
}
于 2019-02-18T01:32:27.970 回答
2

我发现这种对注释视图的重新排序会导致在单击一个时弹出的标注不再位于所有注释之上。我什至尝试对其进行改进,以便使用and而不是bringSubviewToFrontand ,其中第二个参数是列表中的第一个 annotationView。这似乎会导致更少的前后散射,但是在一些注释下仍然会弹出调用。sendSubviewToBackinsertSubview:aboveSubviewinsertSubview:belowSubview:

于 2009-11-05T14:21:11.010 回答
0

我真的需要这样做,并且(当前)答案似乎都没有提供可靠的实现。它们有点工作,但平移地图、选择注释或放大可能会再次弄乱顺序。

最终的、表现良好的解决方案并不是那么简单,所以我将概述我在这里采取的步骤。使用的注释排序MKMapView不尊重添加的顺序,甚至不尊重覆盖annotations属性的顺序。所以...


脚步

• 创建一个CADisplayLink
• 每帧,使用zPosition 和视图在父视图subviews数组中的顺序重新排列注释。
• 如果选择了视图,则在您的排序方案中将其提升到前面
• 点击注释仍然尊重内部MKMapView排序,尽管已经进行了更改。为了解决这个问题,添加一个MKMapViewDelegate
• 在委托对象的mapView:didSelect:方法中,检查所选注释是否是您想要的
• 您可以通过自己对注释运行命中测试来确定正确/优先的注释,并按照您自己的顺序考虑到
• 如果选择的注释是正确的,很好。如果没有,请使用手动选择正确的注释selectAnnotation:animated:


你有它。上述方法似乎运行良好,并且每帧运行此方法对性能的影响也不算太差。您还可以考虑切换到 MapBox,我相信它支持注释排序,但由于各种原因,这并不总是一种选择。

于 2017-09-15T01:54:05.377 回答