自定义 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,fillColor
是 UIColor
,而不是 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
也很好奇。您正在调用一些自定义初始化方法(这很好),但您正在传递 overlay
和 currentPolygon
。但是 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()
}
}
我构建了自定义 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,fillColor
是UIColor
,而不是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
也很好奇。您正在调用一些自定义初始化方法(这很好),但您正在传递 overlay
和 currentPolygon
。但是 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()
}
}