2

I have a MKMapView where I'm tracking the path of the user(it's a running app), but the requirement is create a line with two colors. One for the center of the stroke, and other for the border of the stroke. For this, I'm implementing the method func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer of the UIViewController class, in order to return the renderer.

I'm using Swift 4

Any ideas?

Thanks in advance.

Werem
  • 534
  • 2
  • 5
  • 16

1 Answers1

4

Ok, I reach the solution while writing the question, so I will tell you the solution.

First, you have to create two classes, that extend the MKPolyline class

fileprivate class ForegroundOverlay: MKPolyline{

}
fileprivate class BackgroundOverlay: MKPolyline{

}

Second, you have to modify the event that is triggered on position update

    var positions = [CLLocationCoordinate2D]()
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let userLocation:CLLocation = locations[0] as CLLocation

        positions.append(userLocation.coordinate)

        print("Nuber of locations \(positions.count)")
        print("user latitude = \(userLocation.coordinate.latitude)")
        print("user longitude = \(userLocation.coordinate.longitude)")

        speedIndicator.text = "Speed: \(userLocation.speed * 3.6). Altitude: \(userLocation.altitude)"


        let fPolyLine = BackgroundOverlay(coordinates: positions, count: positions.count)

        mapView.addOverlays([fPolyLine], level: MKOverlayLevel.aboveRoads)

        let bPolyLine = ForegroundOverlay(coordinates: positions, count: positions.count)

        mapView.addOverlays([bPolyLine], level: MKOverlayLevel.aboveRoads)

    }

Third, you have to ask if the polyline is one or another class.

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    let renderer = MKPolylineRenderer(polyline: overlay as! MKPolyline)
    if overlay is ForegroundOverlay {
        renderer.strokeColor = UIColor(red: 230/255, green: 230/255, blue: 1, alpha: 0.5)
        renderer.lineWidth = 10
    } else {
        renderer.strokeColor = UIColor(red: 0, green: 0, blue: 1, alpha: 0.5)
        renderer.lineWidth = 30
    }

    return renderer
}

The result will look like this

enter image description here

Werem
  • 534
  • 2
  • 5
  • 16
  • Nice catch, but in case anyone has to be more dynamic (I mean e.g. display custom colors that came from the backend), this isn't the best approach, since for every color you have to make a subclass. I rewrote a more generic solution after hours of pain: https://stackoverflow.com/a/68830861. Cheers! – jason d Aug 18 '21 at 12:37