When we were tasked with showing a map with a route highlighted on it, we initially went to the Xamarin articles you’ve no doubt come across already. The issue with these was that it didn’t seem to show you where you might get the route coordinates from but just gave some arbirtrary values that they used.
We wanted to know given point A and point B where could you source the necessary route coordinates from in order to display a highlighted route on a map using the Xamarin.Forms.Maps plugin.
In summary here is how to do it…
Step one
Follow the instructions on the xamarin tutorial https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/maps/map-overlay/polyline/
Step two
Link up to the Google API
You’ll need the directions API and we wrote some code to help us, I won’t post it all so you’ll have to do some of the work yourself.
public async Task<WayPoints> GetWayPointsAsync(string FromAddress, string ToAddress){var d = await GetClient<WayPoints>(“directions/json?origin=” + FromAddress + “&destination=” + ToAddress);return d;}
public static List<Position> DecodePolyline(string encodedPoints){if (string.IsNullOrEmpty(encodedPoints))throw new ArgumentNullException(“encodedPoints”);char[] polylineChars = encodedPoints.ToCharArray();int index = 0;int currentLat = 0;int currentLng = 0;int next5bits;int sum;int shifter;List<Position> polylinesPosition = new List<Position>();while (index < polylineChars.Length){// calculate next latitudesum = 0;shifter = 0;do{next5bits = (int)polylineChars[index++] – 63;sum |= (next5bits & 31) << shifter;shifter += 5;} while (next5bits >= 32 && index < polylineChars.Length);if (index >= polylineChars.Length)break;currentLat += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);//calculate next longitudesum = 0;shifter = 0;do{next5bits = (int)polylineChars[index++] – 63;sum |= (next5bits & 31) << shifter;shifter += 5;} while (next5bits >= 32 && index < polylineChars.Length);if (index >= polylineChars.Length && next5bits >= 32)break;currentLng += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1);polylinesPosition.Add(new Position(Convert.ToDouble(currentLat) / 1E5, Convert.ToDouble(currentLng) / 1E5));}return (polylinesPosition);}
var ways = await GoogleService.Current.GetWayPointsAsync(await Trip.StartDetails?.GetAddressAsync(), await Trip.EndDetails?.GetAddressAsync());foreach (var way in ways.routes){customMap.RouteCoordinates = GoogleService.DecodePolyline(way.overview_polyline.points);……..
public event EventHandler RouteUpdated;public virtual void OnRouteUpdated(EventArgs e){RouteUpdated?.Invoke(this, e);}public List<Position> RouteCoordinates { get; set; }The renderer for android looks like this: note that that the if statement is redundant because I was testing out another method here. The code should enter the else statementprotected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e){base.OnElementChanged(e);if (e.OldElement != null){map.InfoWindowClick -= OnInfoWindowClick;}if (e.NewElement != null){formsMap = (CustomMap)e.NewElement;customPins = formsMap.CustomPins;routeCoordinates = formsMap.RouteCoordinates;((MapView)Control).GetMapAsync(this);formsMap.PinsUpdated += FormsMap_PinsUpdated;formsMap.RouteUpdated += FormsMap_RouteUpdated;}}private void FormsMap_RouteUpdated(object sender, EventArgs e){//Routesif (!string.IsNullOrEmpty(formsMap.encodedPolyLine)){var polylineOptions = new PolylineOptions();polylineOptions.InvokeColor(System.Drawing.Color.Pink.ToArgb());foreach (var position in DecodePolylinePoints(formsMap.encodedPolyLine)){polylineOptions.Add(position);}map.AddPolyline(polylineOptions);}else {routeCoordinates = formsMap.RouteCoordinates;SetRoutePolyline();}}