如何在MKMapView上使用MKOverlayView绘制弧/曲线

时间:2011-04-15 06:53:08

标签: iphone ios ipad mapkit mkmapview

现在需要帮助。 我可以使用MKPolyline和MKPolylineView绘制线条,但是如何在MKMapView上的两个坐标之间绘制弧线或曲线? 非常感谢。

最终解决方案

最后,我在这里写下了这些结论,以帮助想要它的人。

如果你想:

  1. 只需在地图上绘制弧形路径
  2. 只在地图上绘制图像
  3. 将弧形路径和图像组合为地图上的叠加层
  4. 所以解决方案是:

    1. MKPolyline MKPolylineView 来绘制线条, MKPolygon MKPolygonView 来绘制多边形, MKCircle MKCircleView 来绘制圆圈。没人适合?弧线在哪里?哦,是的。现在真正的解决方案:您创建一个派生自 MKOverlayPathView 的自定义类并覆盖 -createPath 方法,在 -createPath 中创建一个弧使用 CGContextAddArcToPoint 或您喜欢的其他功能,并将您刚刚创建的路径与 MKOverlayPathView 的路径属性相关联,并完成自定义工作。然后在地图中添加MKPolyline(是!只需 MKPolyline !),然后在 -mapView:viewForOverlay:方法中创建自定义类获取该折线。然后,只需运行它,一切都按照您的意愿运行。魔法?你可以画一个 MKPolyline 作为弧!
    2. 只是一张图片?使用 MKAnnotationView 。那已经完成了!你能行的!我相信!
    3. 在我的问题中,我想在叠加层中绘制一个带有图像的圆弧。因此,我创建了一个符合 MKOverlay 协议的自定义类,以及一个从 MKOverlayView 派生的自定义类来绘制该叠加层。一切正常,但我不能在地图上绘制任何路径!我将lineWidth设置为1,2,3,4 ...但它不起作用!啊..解决方案是使用 MKRoadWidthAtZoomScale(zoomScale)功能设置线宽,您可以看到路径!那已经完成......
    4. 这里有一些提示:

      1. 使用Core Graphic绘制路径,而不是MapKit坐标和UIView坐标!
      2. 在CG功能中,请记住线宽应该由此函数转换: MKRoadWidthAtZoomScale(zoomScale)
      3. 希望帮助

4 个答案:

答案 0 :(得分:1)

阅读文档,您似乎可以创建MKOverlayPathView的实例,并为其CGPathRef属性分配任意path个对象。此路径可以包含直线和圆弧。

我不知道(并且文档没有提及)路径坐标应该是什么格式(MKMapPointCLLocationCoordinate2D会想到)但你可能会发现它通过试验一点。

答案 1 :(得分:1)

你已经在评论中回答了自己,但是我想指出每个人都参与GitHub上的优秀AIMapViewWrapper项目,其中包括sample code用于在一组坐标上绘制弧形路径。在该项目中,它用于绘制平面所包含的路径,包括其下方的阴影路径(以及其他内容,例如沿该路径设置平面动画)。对于任何对此进行刺杀的人来说应该派上用场。

答案 2 :(得分:0)

在回答问题之前,重要的是要提到MKOverlayView已过时,并且从iOS7开始,以后我们应该使用MKOverlayRenderer

在iOS 7和更高版本中,请改用MKOverlayRenderer类显示叠加层。

我们现在可以按实现弧/曲线的方式细分它:

  1. 首先,我们需要定义并添加多边形线。让我们创建一个具有2个坐标的坐标:
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)
  1. 添加折线后,MKMapView将希望我们提供与在第1节中创建的MKOverlayRenderer相对应的适当MKPolyline。我们需要的method是:

mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer

基本上是:

向委托委托一个渲染器对象,以绘制指定的叠加层。

  1. 因此,让我们提供该对象。我们将希望将MKOverlayPathRenderer子类化,该子类显然是从MKOverlayRenderer继承的,并作为文档说明:

当叠加层的形状由CGPath对象定义时,请使用此渲染器。默认情况下,此渲染器填充叠加层的形状,并使用其当前属性表示路径的笔触。

因此,如果我们按原样使用新的子类对象,则会得到一个即用的解决方案,它是从第1节中定义的第一个坐标到第二个坐标的实线。我们想要一条曲线,我们将不得不为此重写一个方法:

您可以按原样使用此类或子类来定义其他图形行为。如果您是子类,请重写createPath()方法并使用该方法构建适当的路径对象。要更改路径,请使其无效并使用子类获得的任何新数据重新创建路径。

这意味着在我们的CustomObject: MKOverlayPathRenderer内部,我们将覆盖createPath

override func createPath() {
 // Getting the coordinates from the polyline
 let points = polyline.points()
 // Taking the center of the polyline (between the 2 coordiantes) and converting to CGPoint
 let centerMapPoint = MKMapPoint(polyline.coordinate)
 // Converting coordinates to CGPoint corresponding to the specified point on the map
 let startPoint = point(for: points[0])
 let endPoint = point(for: points[1])
 let centerPoint = point(for: centerMapPoint)

 // I would like to thank a co-worker of mine for the controlPoint formula :)
 let controlPoint = CGPoint(x: centerPoint.x + (startPoint.y - endPoint.y) / 3,
                            y: centerPoint.y + (endPoint.x - startPoint.x) / 3)

 // Defining our new curved path using Bezier path
 let myPath = UIBezierPath()
 myPath.move(to: startPoint)
 myPath.addQuadCurve(to: endPoint,
                     controlPoint: controlPoint)
 // Mutates the solid line with our curved one
 path = myPath.cgPath
}

我们基本完成了。您可能要考虑添加宽度/笔划/颜色等,以便可以看到曲线

  1. (可选)如果您对渐变曲线感兴趣,则有一个非常好的解决方案here,但是您必须在代码中进行2项更改才能使其起作用:

4.1。覆盖override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext)之后,就在添加渐变之前,您将必须从第3节中添加相同的代码,但是不必更改内部的path,而必须将其添加到提供的上下文中:

context.move(to: startPoint)
context.addQuadCurve(to: endPoint,
                     control: controlPoint)

这基本上为我们提供了有关渐变着色所需的曲线。

4.2。除了使用path.boundingBoxOfPath之外,我们还需要使用path.boundingBox,因为:

... (包括贝塞尔曲线和二次曲线的控制点)。

boundingBoxOfPath不同:

... ,包括贝塞尔曲线和二次曲线的控制点。

希望有帮助:)

答案 3 :(得分:0)

如果要:

  1. 只需在地图上绘制弧形路径
  2. 只需在地图上绘制图像
  3. 将弧形路径和图像组合在地图上

因此解决方案是:

  1. MKPolyline MKPolylineView 可以绘制线条, MKPolygon MKPolygonView 可以绘制多边形, MKCircle MKCircleView 绘制圆圈。没有人适合吗?弧线在哪里?哦是的现在真正的解决方案是:创建一个从 MKOverlayPathView 派生的自定义类,并覆盖 -createPath 方法,在 -createPath 中创建一个弧形使用 CGContextAddArcToPoint 或您喜欢的其他函数,并将您刚创建的路径与 MKOverlayPathView 的path属性相关联,即可完成自定义工作。然后在地图中添加MKPolyline(是的!只需 MKPolyline !),然后在 -mapView:viewForOverlay:方法中,创建自定义类并采用该折线。然后,只要运行它,一切就可以按照您的意愿运行。魔法?您可以绘制 MKPolyline 作为弧!
  2. 只是图像?使用 MKAnnotationView 。大功告成!你能行的!我相信!
  3. 在我的问题中,我想用叠加层中的图像绘制圆弧。因此,我创建了一个符合 MKOverlay 协议的自定义类,并创建了一个由 MKOverlayView 绘制的自定义类。一切正常,但我无法在地图上绘制任何路径!我已经将lineWidth设置为1,2,3,4 ...但是这行不通!嗯..解决方案是通过 MKRoadWidthAtZoomScale(zoomScale)函数设置线宽的,您可以看到路径!完成了……

这里还有一些提示:

  1. 使用Core Graphic绘制路径,而不是MapKit坐标或UIView坐标!
  2. 请记住,在CG函数中,线宽应通过此函数转换: MKRoadWidthAtZoomScale(zoomScale)
  3. 希望能提供帮助