|
|
@@ -14,32 +14,63 @@ class ArrowPolylineRenderer: MKPolylineRenderer {
|
|
|
// 箭头属性
|
|
|
var arrowColor: UIColor = .red
|
|
|
var arrowSize: CGFloat = 8
|
|
|
- var arrowSpacing: CGFloat = 30 // 默认值
|
|
|
+ var arrowSpacing: CGFloat = 30
|
|
|
|
|
|
// 边框属性
|
|
|
- var borderWidth: CGFloat = 0
|
|
|
- var borderColor: UIColor = .clear
|
|
|
+ var borderWidth: CGFloat = 0 {
|
|
|
+ didSet {
|
|
|
+ invalidatePath()
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
|
|
|
- // 1. 绘制边框
|
|
|
- if borderWidth > 0 {
|
|
|
- context.saveGState()
|
|
|
- // 边框宽度 = 主线条宽度 + 2倍边框宽度(左右各扩展 borderWidth)
|
|
|
- let borderLineWidth = lineWidth + borderWidth * 2
|
|
|
- context.setLineWidth(borderLineWidth)
|
|
|
- context.setStrokeColor(borderColor.cgColor)
|
|
|
- context.setLineCap(lineCap) // 保持与主线条一致的线帽样式
|
|
|
- context.setLineJoin(lineJoin) // 保持与主线条一致的拐角样式
|
|
|
- // 绘制边框线条
|
|
|
- super.draw(mapRect, zoomScale: zoomScale, in: context)
|
|
|
- context.restoreGState()
|
|
|
+ var borderColor: UIColor = .clear {
|
|
|
+ didSet {
|
|
|
+ invalidatePath()
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
|
|
|
+ // 1. 绘制边框(如果启用)
|
|
|
+ if borderWidth > 0 {
|
|
|
+ context.saveGState()
|
|
|
+
|
|
|
+ // 设置边框样式
|
|
|
+ context.setLineWidth(lineWidth + borderWidth * 2)
|
|
|
+ context.setStrokeColor(borderColor.cgColor)
|
|
|
+ context.setLineCap(lineCap)
|
|
|
+ context.setLineJoin(lineJoin)
|
|
|
+
|
|
|
+ // 创建路径并描边
|
|
|
+ let path = createPath(for: polyline, in: mapRect, zoomScale: zoomScale)
|
|
|
+ context.addPath(path)
|
|
|
+ context.strokePath()
|
|
|
+
|
|
|
+ context.restoreGState()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 绘制主线条
|
|
|
+ super.draw(mapRect, zoomScale: zoomScale, in: context)
|
|
|
+
|
|
|
+ // 3. 绘制箭头
|
|
|
+ drawArrows(mapRect: mapRect, zoomScale: zoomScale, in: context)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private func createPath(for polyline: MKPolyline, in mapRect: MKMapRect, zoomScale: MKZoomScale) -> CGPath {
|
|
|
+ let path = CGMutablePath()
|
|
|
+ let points = polyline.points()
|
|
|
|
|
|
- // 2. 绘制主轨迹线
|
|
|
- super.draw(mapRect, zoomScale: zoomScale, in: context)
|
|
|
+ // 添加第一个点
|
|
|
+ let firstPoint = self.point(for: points[0])
|
|
|
+ path.move(to: firstPoint)
|
|
|
|
|
|
- // 3. 绘制箭头(数量减半)
|
|
|
- drawArrows(mapRect: mapRect, zoomScale: zoomScale, in: context)
|
|
|
+ // 添加剩余点
|
|
|
+ for i in 1..<polyline.pointCount {
|
|
|
+ let point = self.point(for: points[i])
|
|
|
+ path.addLine(to: point)
|
|
|
+ }
|
|
|
+
|
|
|
+ return path
|
|
|
}
|
|
|
|
|
|
private func drawArrows(mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
|
|
|
@@ -51,10 +82,6 @@ class ArrowPolylineRenderer: MKPolylineRenderer {
|
|
|
var distance: CGFloat = 0
|
|
|
let points = polyline.points()
|
|
|
|
|
|
- // 使用stride跳过每隔一个的箭头
|
|
|
- let step = 2 // 跳过间隔
|
|
|
- var arrowIndex = 0
|
|
|
-
|
|
|
for i in 0..<polyline.pointCount-1 {
|
|
|
let startPoint = point(for: points[i])
|
|
|
let endPoint = point(for: points[i+1])
|
|
|
@@ -68,22 +95,18 @@ class ArrowPolylineRenderer: MKPolylineRenderer {
|
|
|
let arrowCount = Int(floor((distance + segmentLength) / scaledArrowSpacing))
|
|
|
|
|
|
for j in 0..<arrowCount {
|
|
|
- // 只绘制每隔step个箭头
|
|
|
- if arrowIndex % step == 0 {
|
|
|
- let position = CGFloat(j) * scaledArrowSpacing - distance
|
|
|
- let ratio = position / segmentLength
|
|
|
-
|
|
|
- guard ratio >= 0 && ratio <= 1 else { continue }
|
|
|
-
|
|
|
- let arrowPoint = CGPoint(
|
|
|
- x: startPoint.x + dx * ratio,
|
|
|
- y: startPoint.y + dy * ratio
|
|
|
- )
|
|
|
-
|
|
|
- let angle = atan2(dy, dx)
|
|
|
- drawSingleArrow(at: arrowPoint, angle: angle, size: scaledArrowSize, in: context)
|
|
|
- }
|
|
|
- arrowIndex += 1
|
|
|
+ let position = CGFloat(j) * scaledArrowSpacing - distance
|
|
|
+ let ratio = position / segmentLength
|
|
|
+
|
|
|
+ guard ratio >= 0 && ratio <= 1 else { continue }
|
|
|
+
|
|
|
+ let arrowPoint = CGPoint(
|
|
|
+ x: startPoint.x + dx * ratio,
|
|
|
+ y: startPoint.y + dy * ratio
|
|
|
+ )
|
|
|
+
|
|
|
+ let angle = atan2(dy, dx)
|
|
|
+ drawSingleArrow(at: arrowPoint, angle: angle, size: scaledArrowSize, in: context)
|
|
|
}
|
|
|
|
|
|
distance = (distance + segmentLength).truncatingRemainder(dividingBy: scaledArrowSpacing)
|