在回答问题之前,重要的是要提到 MKOverlayView 已被弃用,从 iOS7 及更高版本开始,我们应该使用 MKOverlayRenderer:
在 iOS 7 及更高版本中,改为使用 MKOverlayRenderer 类来显示叠加层。
我们现在可以分解一下如何实现圆弧/曲线:
- 首先,我们需要定义并添加我们的折线。让我们用 2 个坐标创建一个:
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)
- 添加折线后,
MKMapView 将要求我们提供一个正确的MKOverlayRenderer,对应于我们在第 1 节中创建的MKPolyline。我们需要的method 是:
mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
基本上是:
在绘制指定的叠加层时向委托请求要使用的渲染器对象。
- 所以让我们提供那个对象。我们希望继承
MKOverlayPathRenderer 的子类,它显然继承自 MKOverlayRenderer,并且如文档所述:
当您的叠加层的形状由 CGPath 对象定义时,请使用此渲染器。默认情况下,此渲染器填充叠加层的形状并使用其当前属性表示路径的笔触。
因此,如果我们按原样使用新的子类对象,我们将获得一个开箱即用的解决方案,它是从第 1 坐标到我们在第 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
}
我们基本上完成了。您可能需要考虑添加宽度/笔触/颜色等,以便您可以看到曲线。
- (可选)如果您对渐变曲线感兴趣,这里有一个非常棒的解决方案 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.boundingBox,而不是使用path.boundingBoxOfPath,因为:
...包括贝塞尔曲线和二次曲线的控制点。
不同于boundingBoxOfPath:
...不包括贝塞尔曲线和二次曲线的控制点。
希望有帮助:)