How to Draw Two Polylines in Different Colors in Mapkit

How can I show polylines of two or more different pins for one destination?

You can define property to keep track of previously added polylines:

var polylines: [MKPolyline]?

Then, when you update directions, remove the old polylines (if any) from the map, update the polylines with the new values, and then add them to the map:

func updateDirections() {
let request = ...

let directions = MKDirections(request: request)
directions.calculate { response, error in
guard let response = response, error == nil else {
print("\(error)")
return
}

if let polylines = self.polylines {
self.mapView.removeOverlays(polylines)
}

self.polylines = response.routes.map { $0.polyline }
self.mapView.addOverlays(self.polylines!)
}
}

Rendering multiple polylines on MapView

The main problem is in the second for loop:

var fromCoordinateIC :CLLocation = 
CLLocation(latitude: icRouteLat[j],
longitude: icRouteLat[j]) //<-- should be icRouteLong

var toCoordinateIC :CLLocation =
CLLocation(latitude: icRouteLong[j+1], //<-- should be icRouteLat
longitude: icRouteLong[j+1])

The second line is not visible (or not where you expect) because it is getting the wrong coordinates.


There are, however, some additional things (not causing or related to the main issue) I'd like to point out:

  1. In the rendererForOverlay delegate method, the code is using the outside variable routePointer to set the color of the line. This is not recommended. You must not assume when or how often a delegate method will be called. There is no guarantee the delegate method will be called immediately after doing addOverlay. It's also possible for the delegate method to be called multiple times for the same overlay.

    For this reason, you must use data directly associated with the incoming overlay object to set the renderer's properties. In the current example, a better alternative is to set each polyline's title property to "one" or "second" and eliminate the routePointer variable.

  2. In the rendererForOverlay delegate method, it would be better to first check if overlay is of type MKPolyline before treating it like one. You may later want to add other types of overlays such as MKCircle or MKPolygon.

  3. Currently, the code is creating a separate MKPolyline for each line segment in each route. So if route "one" has 10 line segments and route "second" has 15, the code is currently adding 25 overlays. This is not necessary. An MKPolyline can draw multiple line segments. It would be much more efficient to add all the coordinates for a route into an array and after the loop, create and add the MKPolyline. That way, you would only be adding 2 overlays.

    Example of creating a single overlay for each route instead of creating multiple overlays for each route (one for each line segment in the route):

    //First add all the coordinates to an array...
    var coordinates: [CLLocationCoordinate2D] = [CLLocationCoordinate2D]()
    for i in 0 ..< routeLat.count
    {
    var coordinate = CLLocationCoordinate2DMake(routeLat[i], routeLong[i])
    coordinates.append(coordinate)
    }
    //Then create a single overlay with ALL the coordinates in the route...
    polyLine = MKPolyline(coordinates: &coordinates, count: coordinates.count);
    polyLine.title = "one";
    mapView.addOverlay(polyLine);
  4. It's not necessary to define separate arrays for latitude and longitude where each array is a list of doubles. It would be much more efficient and will simplify the code significantly to keep a single array of coordinates (of type CLLocationCoordinate2D) for each route. An MKPolyline can then be created from this array without any looping.

    Example of using single array of CLLocationCoordinate2Ds for each route:

    var routeOneCoordinates = [CLLocationCoordinate2DMake(30.0, -87.0),
    CLLocationCoordinate2DMake(32.0, -84.0),
    CLLocationCoordinate2DMake(31.5, -83.5),
    CLLocationCoordinate2DMake(31.0, -83.0),
    CLLocationCoordinate2DMake(33.5, -82.0)]
    polyLine = MKPolyline(coordinates: &routeOneCoordinates, count: routeOneCoordinates.count);
    polyLine.title = "one";
    mapView.addOverlay(polyLine);

MapKit - Change the Color/Stroke of a MKPolyline

I don't think this is the best solution but I found a way of doing this without removing/adding the overlay.

I keep a reference to the let polyLineRenderer = MKPolylineRenderer(overlay: polyLine) this way on my randomMethod() I can change the properties I need (stroke, lineWidth) and then just execute setNeedsDisplay() on the renderer for that polyline.

Is this worst than the other approach?
It may be.. I have to add a structure to store the renderers, but is the only way I found...



Related Topics



Leave a reply



Submit