Bryan P
Bryan P

Reputation: 4202

How to add border to MKPolyline

Is there a way to add a border to a polyline in apple mapview?

P.S

Just wanna share a solution

Upvotes: 0

Views: 822

Answers (2)

NFC.cool
NFC.cool

Reputation: 3303

public class BorderPathRenderer: MKOverlayPathRenderer {
    
    var polyline: MKPolyline
    var color: UIColor
    var showsBorder: Bool = false
    var borderColor: UIColor = .black
    
    public init(polyline: MKPolyline, color: UIColor) {
        self.polyline = polyline
        self.color = color
        
        super.init(overlay: polyline)
    }
    
    public init(polyline: MKPolyline, color: UIColor, showsBorder: Bool, borderColor: UIColor) {
        self.polyline = polyline
        self.color = color
        self.showsBorder = showsBorder
        self.borderColor = borderColor
        
        super.init(overlay: polyline)
    }
    
    public override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
        let baseWidth: CGFloat = lineWidth / zoomScale
        
        if showsBorder {
            context.setLineWidth(baseWidth * 2)
            context.setLineJoin(CGLineJoin.round)
            context.setLineCap(CGLineCap.round)
            context.addPath(path)
            context.setStrokeColor(borderColor.cgColor)
            context.strokePath()
        }
        
        context.setLineWidth(baseWidth)
        context.addPath(path)
        context.setStrokeColor(color.cgColor)
        context.strokePath()
        
        super.draw(mapRect, zoomScale: zoomScale, in: context)
    }
    
    public override func createPath() {
        let path: CGMutablePath  = CGMutablePath()
        var pathIsEmpty: Bool = true
        
        for i in 0...self.polyline.pointCount - 1 {
            let point: CGPoint = self.point(for: self.polyline.points()[i])
            if pathIsEmpty {
                path.move(to: point)
                pathIsEmpty = false
            } else {
                path.addLine(to: point)
            }
        }
        self.path = path
    }
}

Upvotes: 1

Bryan P
Bryan P

Reputation: 4202

My implementation is to add another polyline overlay underneath the main one that will have a lineWidth a few pixels thicker (your border width we can say) than the main one.

// Instantiate the main polyline
let polylineObj = MKPolyline(coordinates: yourArrayOfCoords, count: yourArrayOfCoords.count)
// Identifier to tell which is which
polylineObj.title = "main"
// Instantiate the border polyline
let borderPolylineObj = MKPolyline(coordinates: yourArrayOfCoords, count: yourArrayOfCoords.count)
// Add main polyline
appleMapView.addOverlay(polylineObj)
// Add border polyline below the main polyline
appleMapView.insertOverlay(borderPolylineObj, below: polylineObj)

Then on the MKMapViewDelegate function:

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    let renderer = MKPolylineRenderer(overlay: overlay)
    // Use different colors for the border and the main polyline
    renderer.strokeColor = overlay.title == "main" ? .blue : .red
    // Make the border polyline bigger. Their difference will be like the borderWidth of the main polyline
    renderer.lineWidth = overlay.title == "main" ? 4 : 6
    // Other polyline customizations
    renderer.lineCap = .round
    renderer.lineJoin = .bevel
    return renderer
}

P.S

If you have a better implementation please do answer. This implementation is expensive to do as this will essentially double the number of polyline being rendered.

Upvotes: 3

Related Questions