// // MapAmapArrowPolylineRenderer.swift // map_amap_ios // // Created by 诺诺诺的言 on 2025/7/22. // import Foundation import MapKit class MapAmapArrowPolylineRenderer: MKPolylineRenderer { // 箭头属性 var arrowColor: UIColor = .red var arrowSize: CGFloat = 8 var arrowSpacing: CGFloat = 30 // 边框属性 var borderWidth: CGFloat = 0 { didSet { invalidatePath() } } 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() // 添加第一个点 let firstPoint = self.point(for: points[0]) path.move(to: firstPoint) // 添加剩余点 for i in 1..= 2 else { return } let scaledArrowSize = arrowSize / zoomScale let scaledArrowSpacing = arrowSpacing / zoomScale var distance: CGFloat = 0 let points = polyline.points() for i in 0.. 2 / zoomScale else { continue } let arrowCount = Int(floor((distance + segmentLength) / scaledArrowSpacing)) for j in 0..= 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) } } private func drawSingleArrow(at point: CGPoint, angle: CGFloat, size: CGFloat, in context: CGContext) { context.saveGState() context.translateBy(x: point.x, y: point.y) context.rotate(by: angle) let arrowPath = UIBezierPath() arrowPath.move(to: CGPoint(x: 3.2, y: 0)) arrowPath.addLine(to: CGPoint(x: 0, y: 2.6)) arrowPath.addLine(to: CGPoint(x: -3.2, y: 2.6)) arrowPath.addLine(to: CGPoint(x: 0, y: 0)) arrowPath.addLine(to: CGPoint(x: -3.2, y: -2.6)) arrowPath.addLine(to: CGPoint(x: 0, y: -2.6)) arrowPath.close() context.setFillColor(arrowColor.cgColor) context.addPath(arrowPath.cgPath) context.fillPath() context.restoreGState() } }