自定义 MKOverlayRenderer drawMapRect 函数不绘制多边形

Custom MKOverlayRenderer drawMapRect function not drawing polygons

我构建了自定义 MKOverlayRenderer 以构建多边形、应用混合模式,然后将它们添加到地图视图。在我的 drawMapRect 函数中,我使用 CGPoints 数组来构建多边形,并创建路径。

但是,在运行时,我的地图视图上没有显示任何内容。我最好的猜测是我在 drawMapRect 函数中创建多边形的顺序。任何帮助或指导将不胜感激,谢谢!

override func drawMapRect(mapRect: MKMapRect, zoomScale: MKZoomScale, inContext context: CGContext) {

    super.drawMapRect(mapRect, zoomScale: zoomScale, inContext: context)
    CGContextSaveGState(context)
    CGContextSetBlendMode(context, CGBlendMode.Exclusion)
    CGContextSetFillColorWithColor(context, self.fillColor)
    CGContextSetStrokeColorWithColor(context, UIColor.whiteColor().CGColor)
    CGContextSetLineWidth(context, 1.0)

    let point = MKMapPointForCoordinate(self.polygon.points[0])
    CGContextMoveToPoint(context, CGFloat(point.x), CGFloat(point.y))
    for i in 1..<self.polygon.points.count {
        let point = polygon.points[i]
        let p = MKMapPointForCoordinate(point)
        CGContextAddLineToPoint(context, CGFloat(p.x), CGFloat(p.y))
    }

    CGContextClosePath(context)
    CGContextDrawPath(context, CGPathDrawingMode.FillStroke)
    CGContextRestoreGState(context)
}

这里是我的自定义叠加渲染器的初始化位置:

func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
    if (overlay is MKPolygon) {
        let polygonRenderer = MyCustomMapRenderer(overlay: overlay, fillColor: self.polyFactory!.getPolygonColor().CGColor, polygon: self.currentPolygon!)
        return polygonRenderer
    }
    return MKOverlayRenderer()
}

几点观察:

  • 您正在使用 points,它已经是 MKMapPoint 的数组(至少在 MKPolygonRenderer 中)并调用 MKMapPointForCoordinate。如果你想使用 MKMapPointForCoordinate,你会传递它 coordinates,而不是 points。也许您已经定义了自己的属性,但我可能会更改 属性 的名称以避免混淆。

  • 您需要使用pointForMapPoint将地图点转换为屏幕点。

  • 此外,您正在调用 CGContextSetFillColorWithColor,但将其传递给 fillColor。但是假设你的 class 是 MKPolygonRenderer 的子 class,fillColorUIColor,而不是 CGColor.

  • 您似乎正在访问某些 属性、points,但 MKPolygonRenderer 没有 points 属性,而是 points() 方法。

综上所述,我什至不清楚您的代码是如何编译的。我怀疑你没有从MKPolygonRenderer subclass,而是subclassed MKOverlayRenderer 然后自己实现了一堆属性?如果你 subclass MKPolygonRender,你可以免费获得所有的多边形行为,只需要实现 drawMapRect:

class MyCustomMapRenderer: MKPolygonRenderer {

    override func drawMapRect(mapRect: MKMapRect, zoomScale: MKZoomScale, inContext context: CGContext) {
        //super.drawMapRect(mapRect, zoomScale: zoomScale, inContext: context)

        CGContextSaveGState(context)
        CGContextSetBlendMode(context, CGBlendMode.Exclusion)
        CGContextSetFillColorWithColor(context, fillColor!.CGColor)
        CGContextSetStrokeColorWithColor(context, UIColor.whiteColor().CGColor)
        CGContextSetLineWidth(context, 1.0)

        if polygon.pointCount > 1 {
            CGContextBeginPath(context)

            let point = pointForMapPoint(polygon.points()[0])
            CGContextMoveToPoint(context, CGFloat(point.x), CGFloat(point.y))
            for i in 1 ..< polygon.pointCount {
                let point = pointForMapPoint(polygon.points()[i])
                CGContextAddLineToPoint(context, CGFloat(point.x), CGFloat(point.y))
            }

            CGContextClosePath(context)
            CGContextDrawPath(context, CGPathDrawingMode.FillStroke)
        }
        CGContextRestoreGState(context)
    }

}

顺便说一句,我们在这里可能会更复杂(检查点是否可见,确定在给定比例下渲染哪些点......即如果具有数千个点的多边形并被缩放为视图的 100x100 部分,也许您不必渲染所有点等)。请参阅 WWDC 2010 Customizing Maps with Overlays,虽然已过时,但仍然具有相关性。

顺便说一句,您的 rendererForOverlay 也很好奇。您正在调用一些自定义初始化方法(这很好),但您正在传递 overlaycurrentPolygon。但是 overlay 多边形,所以我不知道这个 currentPolygon 是什么。 rendererForOverlay 是无状态的,因此我不鼓励您引用一些 属性,而只是采用传递给该方法的 overlay。这样,您可以拥有多个多边形,并让地图视图跟踪哪个是哪个。所以我会做类似的事情:

func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
    if let polygon = overlay as? MKPolygon {
        let polygonRenderer = MyCustomMapRenderer(polygon: polygon)
        polygonRenderer.fillColor = polyFactory!.getPolygonColor()
        return polygonRenderer
    }
    fatalError("Unexpected overlay type")
}

Rob 在 Swift 3

中的回答
class MyRenderer: MKPolylineRenderer {

    override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {

        context.saveGState()
        context.setBlendMode(CGBlendMode.exclusion)

        let clear = UIColor.clear

        context.setFillColor(clear.cgColor)

        let green = UIColor.green

        context.setStrokeColor(green.cgColor)

        context.setLineWidth(10.0)

        if self.polyline.pointCount > 1 {

            context.beginPath()

            let point_ = self.point(for: self.polyline.points()[0])

            context.move(to: CGPoint(x: point_.x, y: point_.y))

            for element in 1 ..< self.polyline.pointCount {

                let point_ = self.point(for: polyline.points()[element])

                context.addLine(to: CGPoint(x: point_.x, y: point_.y))

            }

            context.closePath()

            context.drawPath(using: .fillStroke)

        }

        context.restoreGState()

    }


 }

Rob's answer in Swift 4

class MyCustomMapRenderer: MKPolygonRenderer {

    override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
        //super.drawMapRect(mapRect, zoomScale: zoomScale, inContext: context)

        context.saveGState()
        context.setBlendMode(CGBlendMode.exclusion)
        context.setFillColor(fillColor!.cgColor)
        context.setStrokeColor(UIColor.white.cgColor)
        context.setLineWidth(1.0)

        if polygon.pointCount > 1 {
            context.beginPath()

            let point = self.point(for: polygon.points()[0])
            context.move(to: point)
            for i in 1 ..< polygon.pointCount {
                let point = self.point(for: polygon.points()[i])
                context.addLine(to: point)
            }

            context.closePath()
            context.drawPath(using: CGPathDrawingMode.fillStroke)
        }
        context.restoreGState()
    }

}