Xamarin Forms – How to use Google Maps

  • by
Xamarin_Forms_Google_Maps

In this post we will see how we can use Google Maps in our Xamarin forms project. We will create a Xamarin forms project which will use Maps views, change it to different MapType and place a map marker with address info of the pinned place. For integrating it into our app we need to install two Nuget packages:

You will need Google Maps API key to integrate maps. Head over to Google developer console and obtain a unique "com.google.android.maps.v2.API_KEY" key for your project. See Official post on  How to obtain Google Maps api key?

DOWNLOAD SOURCE CODE

Ok. Let’s start creating our project now. Open your MainPage.xaml form in your project and edit as below.

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsMap.MainPage">

<ContentPage.Content>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">

<Label x:Name="lblInfo" VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand" Margin="5"/>
<Grid x:Name="gridContainer" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="11*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<ContentView x:Name="ContentMap" Grid.Row="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Grid.Row="1" BackgroundColor="DarkGray"
Padding="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Button x:Name="btnStreet" Text="Street" Grid.Column="0" Margin="2" Clicked="BtnMapType_Clicked" BackgroundColor="#fff" TextColor="#000"/>
<Button x:Name="Statellite" Text="Satellite" Grid.Column="1" Margin="2" Clicked="BtnMapType_Clicked" BackgroundColor="#fff" TextColor="#000"/>
<Button x:Name="btnHybrid" Text="Hybrid" Grid.Column="2" Margin="2" Clicked="BtnMapType_Clicked" BackgroundColor="#fff" TextColor="#000"/>
</Grid>

</Grid>
</StackLayout>
</ContentPage.Content>

</ContentPage>

Xamarin_Forms_Google_Maps
This page will contain a Xamarin Content object and three buttons to change our Google Map type (Traffic, Satellite, Hybrid). We will add our map object on this Content control. And will create  method to change map type on pressing any of the buttons. Also a Label to display errors if anything breaks.

Edit its xaml.cs file as below:

MainPage.xaml.cs:

using System;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System.Linq;

namespace XamarinFormsMap
{
public partial class MainPage : ContentPage
{
Xamarin.Forms.Maps.Map map;
public MainPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, true);
this.Title = "Xamarin Forms Google Maps";
LoadMap(19.0605421, 72.8618913);
}

public async void LoadMap(double latitude, double longitude)
{
try
{

var placemarks = await Geocoding.GetPlacemarksAsync(latitude, longitude);

var placemark = placemarks?.FirstOrDefault();

map = new Xamarin.Forms.Maps.Map()
{
Margin = new Thickness(2, 2, 2, 2),
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
MapType = MapType.Street,
HasZoomEnabled = true,
HasScrollEnabled = true,
IsEnabled = true
};

var pin = new Pin()
{
Position = new Xamarin.Forms.Maps.Position(latitude, longitude),
Type = PinType.Place,
Label = placemark.Locality + "",
Address = placemark.CountryName

};

map.Pins.Add(pin);
Position position = new Position();

MapSpan mapSpan = new MapSpan(position, latitude, longitude);
map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(latitude, longitude),
Distance.FromMiles(1)));

StackLayout stackLayout = new StackLayout()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Transparent,
Orientation = StackOrientation.Vertical
};

stackLayout.Children.Add(map);

ContentMap.Content = stackLayout;
ContentMap.IsVisible = true;
gridContainer.IsVisible = true;
lblInfo.Text = "";
lblInfo.IsVisible = false;
}
catch (Exception ex)
{
lblInfo.Text = ex.Message.ToString();
ContentMap.IsVisible = false;
lblInfo.IsVisible = true;
gridContainer.IsVisible = false;
}
}

private void BtnNormal_Clicked(object sender, EventArgs e)
{

}

private void BtnMapType_Clicked(object sender, EventArgs e)
{
try
{
String mapType = ((Button)sender).Text.ToString().ToLower();
switch (mapType)
{
case "hybrid":
map.MapType = MapType.Hybrid;
break;
case "satellite":
map.MapType = MapType.Satellite;
break;
case "street":
map.MapType = MapType.Street;
break;
}

}
catch (Exception ex)
{

}
}
}
}

We are passing a (latitude & longitude) value to our LoadMap() function. Using Xamarin.Essentials.Geocoding we are fetching address information of the passed Latitude and Longitude values. The map Pin will be having Locality & CountryName information on its label. You can extract more information from the “placemark” object of Geocoding class.  We are making a StackLayout and adding our Map control on to it. And finally we will add this stacklayout.

In Android Manifest file add your Google maps API key like below:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" 
          package="com.companyname.XamarinFormsMap" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
	
  
	<application android:label="Xamarin Map">
    <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
    <meta-data android:name="com.google.android.geo.API_KEY" android:value="YOUR-GOOGLE-MAPS-API-KEY" />
		<!--<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="YOUR-GOOGLE-MAPS-API-KEY" />-->
    <!-- Necessary for apps that target Android 9.0 or higher -->
    <uses-library android:name="org.apache.http.legacy" android:required="false" />
  </application>
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>

In MainActivity.cs file, initialize Xamarin.Forms.Map by using Xamarin.FormsGoogleMaps.Init(this, savedInstanceState);

and add permissions to access device location.

MainActivity.cs:

using Android;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using System;

namespace XamarinFormsMap.Droid
{
[Activity(Label = "Xamarin Map", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
const int RequestLocationId = 0;

readonly string[] LocationPermissions =
{
Manifest.Permission.AccessCoarseLocation,
Manifest.Permission.AccessFineLocation
};

protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;

base.OnCreate(savedInstanceState);
Xamarin.FormsGoogleMaps.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}

protected override void OnStart()
{
base.OnStart();

if ((int)Build.VERSION.SdkInt >= 23)
{
if (CheckSelfPermission(Manifest.Permission.AccessFineLocation) != Permission.Granted)
{
RequestPermissions(LocationPermissions, RequestLocationId);
}
else
{
Console.WriteLine("Location permissions already granted.");
}
}
}

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
if (requestCode == RequestLocationId)
{
if ((grantResults.Length == 1) && (grantResults[0] == (int)Permission.Granted))
{
Console.WriteLine("Location permissions granted.");
}
else
{
Console.WriteLine("Location permissions denied.");
}
}
else
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
}

On on Xamarin iOS project, initialize the Maps component by adding Xamarin.FormsGoogleMaps.Init(“GOOGLE_MAPS_API_KEY”) in AppDelegate.cs

AppDelegate.cs:

using Foundation;
using UIKit;

namespace XamarinFormsMap.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
Xamarin.FormsGoogleMaps.Init("GOOGLE_MAPS_API_KEY");
LoadApplication(new App());

return base.FinishedLaunching(app, options);
}
}
}

DOWNLOAD SOURCE CODE