Objective c MapKit(MKMapView):zPosition在iOS11上不再工作

Objective c MapKit(MKMapView):zPosition在iOS11上不再工作,objective-c,mapkit,mkannotation,ios11,mkannotationview,Objective C,Mapkit,Mkannotation,Ios11,Mkannotationview,在iOS11上,zPosition停止了annotationView.layer的工作。每次贴图区域更改时 原始解决方案没有运气:layer.zPosition=X bringViewToFront/SendViewToBack方法没有成功 Xcode 8.3/9 更新(解决方案感谢Elias Aalto): 创建MKAnnotationView时: annotationView.layer.zPosition = 50; if (IS_OS_11_OR_LATER) { anno

iOS11
上,
zPosition
停止了annotationView.layer的工作。每次贴图区域更改时

  • 原始解决方案没有运气:layer.zPosition=X
  • bringViewToFront
    /
    SendViewToBack
    方法没有成功
Xcode 8.3/9

更新(解决方案感谢Elias Aalto):

创建MKAnnotationView时:

annotationView.layer.zPosition = 50;
if (IS_OS_11_OR_LATER) {
    annotationView.layer.name = @"50";
    [annotationView.layer addObserver:MeLikeSingleton forKeyPath:@"zPosition" options:0 context:NULL];

}
在MeLikeSingleton或其他任何观察者对象中:

- (void)observeValueForKeyPath:(NSString *)keyPath
                         ofObject:(id)object
                           change:(NSDictionary *)change
                          context:(void *)context {

       if (IS_OS_11_OR_LATER) {

           if ([keyPath isEqualToString:@"zPosition"]) {
               CALayer *layer = object;
               int zPosition = FLT_MAX;
               if (layer.name) {
                   zPosition = layer.name.intValue;
               }
               layer.zPosition = zPosition;
               //DDLogInfo(@"Name:%@",layer.name);
           }

       } 
}
  • 此解决方案使用layer.name值跟踪zOrder。如果您有多个级别的zPosition(用户位置、群集、pin、标注);)
  • 不适用于循环,仅适用于KVO
  • 我使用了一个观察图层值变化的单例对象。如果您在整个应用程序中使用了多个MKMapView
在IOS11之前它是如何工作的

…是使用

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
并在此处设置zPosition

…但这(对于我们中的一些人来说,仍然不知道为什么)在iOS11中不再起作用了

zPosition确实有效,只是MKMapView在内部根据有点损坏和无用的MKFeatureDisplayPriority覆盖了它。如果您只需要在“其他一切”之上保留一些注释,那么可以使用KVO半干净地完成这项工作。只需在注释视图图层的zPosition中添加一个观察者,并在MKMapView试图摆弄它时覆盖它

(请原谅我的ObjC)

添加观察员:

        [self.annotationView.layer addObserver:self forKeyPath:@"zPosition" options:0 context:nil];
否决MKMapView

 - (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context
{
    if(object == self.annotationView.layer)
    {
        self.annotationView.layer.zPosition = FLT_MAX;
    }
}

利润

我们可以完全忽略
MKMapView
修改
MKAnnotationView
层的
zPosition
的尝试。由于
MKAnnotationView
使用标准
CALayer
作为其层而不是某些私有类,因此我们可以对其子类化并覆盖其
zPosition
。要实际设置
zPosition
,我们可以提供自己的访问器

它将比KVO工作得更快

class ResistantLayer: CALayer {

    override var zPosition: CGFloat {
        get { return super.zPosition }
        set {}
    }
    var resistantZPosition: CGFloat {
        get { return super.zPosition }
        set { super.zPosition = newValue }
    }
}

class ResistantAnnotationView: MKAnnotationView {

    override class var layerClass: AnyClass {
        return ResistantLayer.self
    }
    var resistantLayer: ResistantLayer {
        return self.layer as! ResistantLayer
    }
}
更新:

我有一个非常不雅观的方法,当点击重叠的注释时,选择最上面的注释视图

class MyMapView: MKMapView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

        // annotation views whose bounds contains touch point, sorted by visibility order
        let views =
            self.annotations(in: self.visibleMapRect)
                .flatMap { $0 as? MKAnnotation }
                .flatMap { self.view(for: $0) }
                .filter { $0.bounds.contains(self.convert(point, to: $0)) }
                .sorted(by: {
                    view0, view1 in

                    let layer0  = view0.layer
                    let layer1  = view1.layer
                    let z0      = layer0.zPosition
                    let z1      = layer1.zPosition

                    if z0 == z1 {
                        if  let subviews = view0.superview?.subviews,
                            let index0 = subviews.index(where: { $0 === view0 }),
                            let index1 = subviews.index(where: { $0 === view1 })
                        {
                            return index0 > index1
                        } else {
                            return false
                        }
                    } else {
                        return z0 > z1
                    }
                })

        // disable every annotation view except topmost one
        for item in views.enumerated() {
            if item.offset > 0 {
                item.element.isEnabled = false
            }
        }

        // re-enable annotation views after some time
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            for item in views.enumerated() {
                if item.offset > 0 {
                    item.element.isEnabled = true
                }
            }
        }

        // ok, let the map view handle tap
        return super.hitTest(point, with: event)
    }
}

你找到解决办法了吗?我在处理同样的事情。是的,请看《给同一条船上的每个人的原始帖子:zPosition在iOS 11中显然被破坏了。请花点时间提交一份bug报告:我们中的更多人将提交,这个bug将在苹果得到更多的关注。伙计,你必须热爱苹果,只是彻底打破了每一个主要版本,就像它不超过它一样。这对我来说比使用相当奇怪的
[self.annotationView setDisplayPriority:MKFeatureDisplayPriorityDefaultLow/High]
因为这种方法实际上隐藏了出现在高优先级视图下的低优先级视图,而不仅仅是重新排列它们的z索引-如果是纯色元素,则很好,如果是半透明元素则不好。谢谢!此解决方案开始为我崩溃应用程序。是的,它正在生产中。您确定返回子类吗–不是
MKAnnotationView
–来自
mapView(MKMapView,viewFor:MKAnnotation)
?是的,我返回了正确的子类。我在
ResistantLayer
中的空
集合
中放置了一条
print
语句,随后在
mapView(\uUu∶regionDidChangeAnimated:)的某个地方调用了它
,例如–您正在检查
mapView.annotations的
zPosition
s
?这对群集批注不起作用,您会崩溃。(如果您不需要群集批注,可以正常工作!)@不知道为什么?我正在返回群集批注的
mkmarkernotationview
子类,找到空
zPosition.set
,没有崩溃发生。