2013-12-16 7 views
9

iOS 7 MapKit API를 사용하여 MKDirectionsRequest가 생성 한 경로를 표시하는지도에서 3D 카메라 이동을 생성합니다. 경로는 다음과 같이 MKOverlayRenderer에서 렌더링됩니다.MKPolylineRenderer가 들쭉날쭉하고 불균등 한 경로를 생성합니다.

-(void)showRoute:(MKDirectionsResponse *)response 
{ 
for (MKRoute *route in response.routes) 
{ 
    [self.map 
    addOverlay:route.polyline level:MKOverlayLevelAboveRoads]; 
} 
} 

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay 
{ 
MKPolylineRenderer *renderer = 
[[MKPolylineRenderer alloc] initWithOverlay:overlay]; 
UIColor *mapOverlayColor = [UIColor colorWithRed:((float)22/255.0f) green:((float)126/255.0f) blue:((float)251/255.0f) alpha:0.8]; 
renderer.strokeColor = mapOverlayColor; 
renderer.lineWidth = 13.0; 
return renderer; 
} 

하나의 문제를 제외하고는 잘 작동합니다.

screen shot http://f.cl.ly/items/3L0s3h0B1v113y3O2p3K/iPhone%20Dec%2015,%202013,%207%3A26%3A33%20PM.png

내가 스위칭 있는지 확인하기 위해 테스트 : 나는 확대 또는 MKMapCameras와 경로의 초점을 이동하면 (그들없이 단순히 사용자로 그렇게 할 경우)이 스크린 샷에서와 같이 경로가 고르지입니다 MKOverlayLevelAboveLabels에 차이가 있지만 슬프게도 결과는 같습니다.

누구나 렌더링을 개선하는 방법에 대한 제안이 있습니까? 측지선 경로로 전환하면 차이가 발생합니까? 그렇다면 어떻게 구현합니까?

+0

MKGeodesicPolyline으로 전환해도 다른 점이 없습니다. 하지만 MKGolodesicPolyline에서 polylineWithXXX를 호출한다는 점을 제외하면 MKPolyline과 같은 방식으로 생성되지만 렌더러는 여전히 MKPolylineRenderer입니다. – Anna

답변

2

일단지도에 선을 그으면 사용자가 확대하면 다시 렌더링되지 않을 수 있습니다. 그렇지 않으면 사용자가 확대/축소를 완료하기 전에 다시 렌더링 될 수 있습니다. 이 경우 줌 후 너비는 더 이상 원하는 너비를 미터로 반영하지 않습니다. 이를 처리하는 한 가지 방법은 regionDidChangeAnimated를 재정의하고 오버레이를 제거하고 다시 추가하는 것입니다.

3

서브 클래스 MKPolylineRenderer 및 applyStrokePropertiesToContext를 오버라이드 (override) : atZoomScale : 그것은 규모를 무시하고 일정한 폭에 선을 그립니다 있도록 : 이제

@interface ConstantWidthPolylineRenderer : MKPolylineRenderer 
@end 

@implementation ConstantWidthPolylineRenderer 

- (void)applyStrokePropertiesToContext:(CGContextRef)context 
          atZoomScale:(MKZoomScale)zoomScale 
{ 
    [super applyStrokePropertiesToContext:context atZoomScale:zoomScale]; 
    CGContextSetLineWidth(context, self.lineWidth); 
} 

@end 

이 그것을 사용하고 부드러운 렌더링 존경 :

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay 
{ 
    MKPolyline *polyline = (MKPolyline *)overlay; 
    ConstantWidthPolylineRenderer *renderer = [[ConstantWidthPolylineRenderer alloc] initWithPolyline:polyline]; 
    renderer.strokeColor = [UIColor redColor]; 
    renderer.lineWidth = 40; 
    return renderer; 
} 
+1

이 솔루션은 고정 선 너비 만 갖기 때문에 확대/축소 관련 문제가있을 수 있습니다. 확대/축소시에는 레벨 이후에 줄이 보이지 않습니다. – Kumar

1

MKPolylineRenderer을 심각하게는 오프 스크린 그리기되지 않습니다 깨진하고이를 화면에 남아있을 수있는 엔드 캡 유물 원인의의 clipRect을 계산하는 잘못된 논리를 가지고있다. 오버레이를 제거하고 읽음으로써 나에게 아무런 영향이 없었습니다. 선 너비를 수정하려고해도 더 큰 선 너비로 끝캡 문제가 계속 발생합니다. roadSizeForZoomLevel 옵션을 사용하면 작동하지 않습니다 (lineWidth = 0)

절대로 멀리 가지 않는 엔드 캡 아티팩트를 제거하려면 Breadcrumb 샘플 앱에서 렌더러를 사용했습니다. 이제지도를 옮길 때 때때로 다시 그리기의 용인 할 수없는 문제가 있습니다.

내가 생각하는 빵 부스러기 렌더러는 PolylineRenderer가되어야한다고 생각하지만 누군가 그것을 부러 뜨 렸습니다. 하지만 심지어는 여전히 명확하지 않은 하나의 오프 스크린 redraws (코어 그래픽 전문가가 아니라 사과지도 응용 프로그램이 애플 리케이션을 제시하지 않는이 사실을 확신하는 전문가가 확실히 그것을 도출 할 수있다.)

어쨌든 적어도 렌더러를 원한다면 화면에 정크를 남겨 두지 않는 것은 빵 부스러기 렌더러를 사용하는 것입니다. 더 나은 맵킷이 정말로 필요한 경우 googmaps를 시도하십시오.

0

OK, 천천히 MKPolylineRenderer 렌더링을 느리게하여이 문제를 해결했습니다. 먼저 Breadcrumb 렌더러 [Apple breadcrumb sample] [1] https://developer.apple.com/library/content/samplecode/Breadcrumb/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010048-Intro-DontLinkElementID_2

포인트를 동적으로 CrumpPath는 경로를 추가하기 만하면됩니다.

둘째, MKPolylines가 잘못된 렌더링을 수정 했으므로 속도가 매우 느려야하므로 속도를 높여야합니다.

정적 dispatch_once_t onceToken (이건 그냥 신속하고 더러운입니다) https://stackoverflow.com/a/28964449/7313127

는 "CrumbPathRenderer"그냥이가 drawMapRect 기능에 C 코드를 obj에 추가로이 적응;

스택 오버 플로우에이 답변을 참조하십시오

dispatch_once (& onceToken,^{

CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)]; 

    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 
}); 

setNeedsDisplay

호출 렌더러에 업데이트 방법 작성 - (무효) 업데이트 {

[self setNeedsDisplay]; 

}

을 나는 renderer.setNeedsDisplay를 넣는다. 아마

FUNC의지도보기 (_지도보기) 필요하지 S : MKMapView, 애니메이션 regionWillChangeAnimated : BOOL)를

{

crumbRenderer.setNeedsDisplay() 

}

중요 참고 :이 완벽하게 렌더링하지만 100을 사용합니다 % CPU. 따라서 휴대 전화의 배터리를 소모하지 않고 CPU를 스 래시 (thrash)하기 위해 업데이트 방법에서 정적 및 유일한 호출을 유지하려면 디스플레이 링크가 세 번째로 호출 할 때마다 setNeedsDisplay를 호출하십시오. CA 디스플레이 링크는 하드웨어 새로 고침 타이머임을 기억하십시오.

알아두면 나날이 걸리는 (성급하게 작성된) 답변을 따르면 대략 30 %의 CPU와 맵 경로가 사용되지 않을 것입니다.

안녕하세요 사과, MKMapView 수정을 원하십니까?

2

확대/축소가 변경되거나 영역이 변경되면 MKPolyline이 그리기되지 않습니다. 아래 간단한 수정.

public class PolylineRenderer : MKPolylineRenderer { 

    private var displayLink: CADisplayLink! 
    private var ticks = 0 

    override public init(overlay: MKOverlay) { 
     super.init(overlay: overlay) 

     displayLink = CADisplayLink(target: self, selector:#selector(PolylineRenderer._update)) 
    displayLink.add(to: .main, forMode: .commonModes) 
    } 

    func _update() { 
     if ticks < 3 { 
      ticks+=1 
     } else { 
      ticks = 0 
     } 

     if ticks == 0 { 
      self.setNeedsDisplay() 
     } 
    } 

    deinit { 
     if displayLink != nil { 
      displayLink.invalidate() 
     } 
    } 
} 

매우 간단합니다. 3 틱을 건너 뛰어도 CPU와 삐걱 거리는 소리가 나지 않습니다.

1

스위프트 3 솔루션 :

그런 다음 MKPolylineRenderer

의 서브 클래스
class CustomPolyline: MKPolylineRenderer { 

    override func applyStrokeProperties(to context: CGContext, atZoomScale zoomScale: MKZoomScale) { 
     super.applyStrokeProperties(to: context, atZoomScale: zoomScale) 
     UIGraphicsPushContext(context) 
     if let ctx = UIGraphicsGetCurrentContext() { 
      ctx.setLineWidth(self.lineWidth) 
     } 
    } 

} 

를 작성하여 rendererFor MapKit 위임에 사용 :

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { 
     let renderer = CustomPolyline(overlay: overlay) 
     renderer.strokeColor = UIColor.red 
     renderer.lineWidth = 100 
     return renderer 
} 

귀하의 폴리 라인이 확대 후 다시 렌더링되지 않습니다 따라서 인공물을 피하십시오.