[英]How to draw arc/curve line with MKOverlayView on MKMapView
Help needed now.现在需要帮助。 I can draw lines with MKPolyline and MKPolylineView, but how to draw an arc or curve lines between two coordinates on the MKMapView?
我可以用 MKPolyline 和 MKPolylineView 画线,但是如何在 MKMapView 上的两个坐标之间画弧线或曲线? Great thanks.
万分感谢。
You answered yourself in your comment already, but I'd like to point everyone at the excellent AIMapViewWrapper project on GitHub which includes sample code for plotting an arc path over a set of coordinates.您已经在评论中回答了自己,但我想向大家指出 GitHub 上优秀的AIMapViewWrapper项目,其中包括用于在一组坐标上绘制圆弧路径的示例代码。 In that project it's being used to draw the path a plane takes including a shadow path underneath it (and other stuff such as animating a plane along that path).
在那个项目中,它被用来绘制平面所采用的路径,包括它下面的阴影路径(以及其他东西,例如沿该路径为平面设置动画)。 Should come in handy for anyone taking a stab at this.
任何人都应该派上用场。
Reading the documentation, it seems that you can create an instance of MKOverlayPathView
and assign an arbitrary CGPathRef
object to its path
property.阅读文档,似乎您可以创建
MKOverlayPathView
的实例并将任意CGPathRef
对象分配给其path
属性。 This path can contain both straight lines and arcs.该路径可以包含直线和圆弧。
I don't know (and the documentation doesn't mention) in what format the coordinates of the path should be ( MKMapPoint
or CLLocationCoordinate2D
come to mind) but you can probably find that out by experimenting a bit.我不知道(并且文档没有提到)路径的坐标应该是什么格式(
MKMapPoint
或CLLocationCoordinate2D
),但您可能可以通过一些试验找到MKMapPoint
。
Before answering the question it is important to mention that MKOverlayView is deprecated and from iOS7 and later we should use MKOverlayRenderer :在回答这个问题之前,重要的是要提到MKOverlayView已被弃用,并且从 iOS7 和更高版本开始,我们应该使用MKOverlayRenderer :
In iOS 7 and later, use the MKOverlayRenderer class to display overlays instead.
在 iOS 7 及更高版本中,请改用 MKOverlayRenderer 类来显示叠加层。
We can now break it down on how to implement the arc/curve line:我们现在可以将其分解为如何实现圆弧/曲线线:
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)
MKMapView
will want us to provide a proper MKOverlayRenderer
in corresponding to the MKPolyline
we've created at section 1. The method we need is:MKMapView
会要求我们提供一个合适的MKOverlayRenderer
对应于我们在第 1 部分创建的MKPolyline
。我们需要的方法是: mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
Which basically:基本上:
Asks the delegate for a renderer object to use when drawing the specified overlay.
在绘制指定的叠加层时向委托请求渲染器对象。
MKOverlayPathRenderer
which obviously inherits from MKOverlayRenderer
and as documentation states:MKOverlayPathRenderer
这显然继承自MKOverlayRenderer
和文档状态:Use this renderer when your overlay's shape is defined by a CGPath object.
当您的叠加层的形状由 CGPath 对象定义时,请使用此渲染器。 By default, this renderer fills the overlay's shape and represents the strokes of the path using its current attributes.
默认情况下,此渲染器填充叠加层的形状并使用其当前属性表示路径的笔划。
So if we will use our newly subclass object as is, we will get an out-of-the-box solution which is a solid line from the 1st coordinate to the 2nd one we've defined in section 1, but since we want a curved line we will have to override a method for that:因此,如果我们按原样使用我们新的子类对象,我们将得到一个开箱即用的解决方案,它是从第 1 节中定义的第一个坐标到第二个坐标的实线,但由于我们想要一个曲线,我们将不得不为此重写一个方法:
You can use this class as-is or subclass to define additional drawing behaviors.
您可以按原样或子类使用此类来定义其他绘图行为。 If you subclass, override the createPath() method and use that method to build the appropriate path object.
如果是子类,则覆盖 createPath() 方法并使用该方法构建适当的路径对象。 To change the path, invalidate it and recreate the path using whatever new data your subclass has obtained.
要更改路径,请使其无效并使用您的子类获得的任何新数据重新创建路径。
It means that inside our CustomObject: MKOverlayPathRenderer
we will override 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
}
We are basically done.我们基本上完成了。 You might want to consider adding width/stroke/color etc so you could see the curved line .
您可能需要考虑添加宽度/笔触/颜色等,以便您可以看到曲线。
4.1. 4.1. After overriding
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext)
, just before adding the gradient, you will have to add the same code from section 3 but instead of changing the inner path
you will have to add it to the provided context:在覆盖
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext)
,就在添加渐变之前,您必须添加第 3 节中的相同代码,但不是更改内部path
而是必须添加它提供的上下文:
context.move(to: startPoint)
context.addQuadCurve(to: endPoint,
control: controlPoint)
This basically gives us a curved line we need regarding the gradient coloring.这基本上为我们提供了一条关于渐变着色所需的曲线。
4.2. 4.2. Instead of using
path.boundingBoxOfPath
we will need to use path.boundingBox
because:而不是使用的
path.boundingBoxOfPath
我们将需要使用path.boundingBox
因为:
... including control points for Bézier and quadratic curves.
...包括贝塞尔曲线和二次曲线的控制点。
Unlike boundingBoxOfPath
:与
boundingBoxOfPath
不同:
... not including control points for Bézier and quadratic curves.
...不包括贝塞尔曲线和二次曲线的控制点。
Hope that helps :)希望有帮助:)
If you want to:如果你想:
So the solutions are:所以解决办法是:
And some tips here:还有一些提示:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.