2017-10-02 23 views
12

iOS11에서 zPosition은 annotationView.layer에서 작동이 중지되었습니다. 지도 영역이 바뀔 때마다.MapKit (MKMapView) : iOS11에서 z 위치가 더 이상 작동하지 않습니다.

  • enter image description here 원래의 솔루션으로 운 : layer.zPosition = X;

  • bringViewToFront/SendViewToBack 방법

Xcode 8.3/9

UPDATE (솔루션 덕분 엘리아스 알토)와 운 :

하는 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); 
      } 

     } 
} 
  • 이 솔루션은 zOrder를 추적 할 layer.name 값을 사용합니다.
  • 루프 전용, KVO 만
  • 레이어 값 변경을 관찰하는 싱글 톤 개체를 사용했습니다. 사용자 지정 위치 (클러스터 위치, 클러스터, 핀, 콜 아웃)가 여러 개인 경우에 유용합니다. 여러 개의 MKMapView가 앱을 통해 사용되는 경우에 사용합니다. IOS11

    ..is가

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

    를 사용하고 여기에 zPosition을 설정하기 전에

것은 IT는 일하는 방법.

..하지만 iOS11에서는 더 이상 작동하지 않습니다.

+2

해결 방법을 찾으셨습니까? 나는 똑같은 것을 다루고있다. – d3020

+0

예, 원래 게시글을 참조하십시오. – Jaro

+0

동일한 보트에있는 모든 사람들에게 : z 위치는 iOS 11에서 분명히 깨졌습니다. 버그 보고서를 제출 하시려면 시간을내어주십시오. https://developer.apple.com/bug-reporting/ 더 많은 정보를 보내주십시오. 파일, 더 많은 관심이 버그는 애플에서 얻을 것이다. – Stack

답변

6

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

이익을

+0

그 방법은 저의 z- 인덱스를 재정렬하는 것보다 우선 순위가 높은 뷰 아래에 나타나는 낮은 우선 순위의 뷰를 숨기고 있기 때문에 꽤 이상한'[self.annotationView setDisplayPriority : MKFeatureDisplayPriorityDefaultLow/High] '를 사용하는 것보다 훨씬 효율적입니다. 그것의 솔리드 컬러 요소지만 반투명하면 좋지 않습니다. 감사! – Breeno

4

우리는 완전히 MKAnnotationView를 수정하는 MKMapView의 시도를 무시할 수 있습니다 레이어의 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 
    } 
} 

UPDATE : 중복 주석을 두드리고 때 맨 위의 주석 뷰의 선택을위한 하나의 매우 우아 방법을 가지고

.

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) 
    } 
} 
+0

테스트 해 보셨습니까? 나를 위해 작동하지 않는 것 같아요 – onmyway133

+0

예, 생산 중입니다. 'MKAnnotationView'가 아닌'mapView (MKMapView, viewFor : MKAnnotation)'에서 서브 클래스를 반환한다는 것이 긍정적입니까? – bteapot

+0

그래, 나는 올바른 하위 클래스를 반환했다. 나는'ResistantLayer'에서 빈'set '안에'print' 문을 넣었고, 나중에 – onmyway133