我的地图中有几个MKAnnotations(及其相应的视图),有时会非常拥挤。现在,我的应用程序中的注释有两种形式:一些注定要保持原样,而另一些则会随着时间的推移而移动。我希望在背景中有视觉上更稳定的,而移动的那些总是在它们面前传递。
或许会想到,最近添加到地图中的注释会最终到达前面(或者至少在最后面),但这似乎不是规则。据我所知,我首先创建并添加所有非移动注释,然后添加一些新实例化的移动注释,但其中许多(尽管不是全部!)最终都是在永久存货的情况下绘制的。
有趣的是,当时间流逝,但是新的移动注释被创建时,它们倾向于更多地倾向于顶部而不是第一个 - 即使所有移动的注释对象都是在非移动部分已经添加到地图之后创建的
有没有人知道改变地图上注释视图的奇怪自然顺序的技巧?我试图搜索Map Kit API,但似乎没有提到这样的事情。
答案 0 :(得分:40)
好的,对于来自MKMapViewDelegate的解决方案使用方法
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
在此方法中,您应该在将AnnotationView添加到mapKit View后重新排列。 因此,代码可能如下所示:
- (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];
}
}
}
这适合我。
答案 1 :(得分:12)
在iOS 11下,displayPriority
的实施打破了使用bringSubviewToFront
或zPosition
的所有解决方案。
如果覆盖注释视图的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?.bringSubview(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
}
}
}
答案 2 :(得分:11)
尝试在以下位置设置注释视图图层的zPosition(annotationView.layer.zPosition):
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views;
答案 3 :(得分:4)
斯威夫特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.
}
}
希望这有帮助
答案 4 :(得分:2)
我发现重新排序注释视图会导致在单击一个注释时弹出的标注不再位于所有注释之上。我甚至尝试过改进它,以便使用bringSubviewToFront
和sendSubviewToBack
而不是insertSubview:aboveSubview
和insertSubview:belowSubview:
,其中第二个参数是列表中的第一个annotationView。这似乎会导致前后散射更少,但是在一些注释下仍会弹出呼叫。
答案 5 :(得分:2)
在委托功能中,您可以选择将其固定在顶部的针脚:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?` {
...
if my annotation is the special one {
annotationView.isSelected = true
}
...
}
答案 6 :(得分:0)
我真的需要这样做,并且(当前)答案似乎都没有提供可靠的实现。他们有点工作,但平移地图,选择注释或放大可能会再次搞砸订单。
最终的,表现良好的解决方案并非如此微不足道,所以我将概述我在这里采取的步骤。 MKMapView
使用的注释排序不遵守添加的顺序,甚至不包括重写annotations
属性的顺序。所以......
•创建CADisplayLink
•每个帧,使用两者层zPosition重新排序注释,以及超视图的subviews
数组中的视图排序。
•如果选择了视图,请在订购方案中将其提升到前面
•尽管已经进行了更改,但点击注释仍然遵循内部MKMapView
排序。要解决此问题,请添加MKMapViewDelegate
•在委托对象的mapView:didSelect:
方法中,检查所选注释是否符合您的要求
•您可以通过自己对注释运行命中测试来确定正确/优先级的注释,并考虑您自己的顺序
•如果所选注释正确,那么很好。如果没有,请使用selectAnnotation:animated:
你有它。上面的方法看起来效果很好,每帧运行的性能也不算太差。你也可以看看切换到MapBox,我认为它支持注释排序,但由于各种原因,这并不总是一个选项。