Olá, neste post irei demonstrar como você pode adicionar pontos (pins) no maps através de cliques do usuário em aplicações Xamarin.Forms.
Com esses pontos você poderá pegar as coordenadas (Latitude x Longitude) do ponto selecionado pelo usuário.
ADICIONANDO NUGET PACKAGES
Clique com o botão direito em cima de sua Solution e selecione “Manage NuGet Packages for Solution…”.
Digite “Xamarin.Forms.Maps” e selecione o plugin como demonstrado na imagem a seguir.
Selecione todos os projetos e clique no botão “Install”.
Após a instalação do Xamarin.Forms.Maps será necessãrio a instalaçao do pacote GooglePlayServices.Maps apenas para o projeto .Android.
Digite “Xamarin.GooglePlayServices.Maps” e selecione o plugin como demonstrado na imagem a seguir.
Selecione apenas o projeto .Android e clique no botão “Install”.
Adicionando permissões
Android
Edite o manifesto para adicionar algumas permissões, para isso clique com o botão direito no projeto .android e selecione Properties.
No Android Manifest selecione as seguintes permissões.
O passo seguinte é obter uma chave de API do Google API Console e adiciona-la em nosso manifesto. Para isso acesse https://developers.google.com/maps/documentation/android-api/ com uma conta Google.
Selecione “OBTER UMA CHAVE” e em seguida defina um nome para o seu projeto, selecione Yes e clique em CREATE AND ENABLE API.
Copie a API KEY gerada.
Edite o arquivo AndroidManifest.xml e dentro de application, adicione uma meta-data com a API KEY gerada, como demonstrado a seguir.
ANDROIDMANIFEST
<?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.PinClickDemo" android:installLocation="auto"> | |
<uses-sdk android:minSdkVersion="15" /> | |
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> | |
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> | |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> | |
<application android:label="PinClickDemo.Android"> | |
<meta-data android:name="com.google.android.geo.API_KEY" android:value="COLE SUA API KEY AQUI" /> | |
</application> | |
</manifest> |
iOS
No projeto .iOS edite o arquivo Info.plist e adicione as seguintes permissões dentro de “dict” como demonstrado a seguir.
… | |
<key>NSLocationUsageDescription</key> | |
<string>Esse aplicativo precisa acessar a sua localização.</string> | |
<key>NSLocationAlwaysUsageDescription</key> | |
<string>Esse aplicativo precisa acessar a sua localização.</string> | |
<key>NSLocationWhenInUseUsageDescription</key> | |
<string>Esse aplicativo precisa acessar a sua localização.</string> | |
</dict> | |
</plist> |
Portable
Em seu projeto portable crie a classe “ExtendedMap.cs”.
Observe que a classe ExtendedMap está herdando de Xamarin.Forms.Maps.Map.
Crie também a classe TapEventArgs que herda de System.EventArgs.
Dentro de ExtendedMap crie um EventHandler de TapEventArgs chamado Tap e os métodos “OnTap” como demonstrado a seguir.
using System; | |
using Xamarin.Forms.Maps; | |
namespace PinClickDemo | |
{ | |
public class ExtendedMap : Map | |
{ | |
public event EventHandler<TapEventArgs> Tap; | |
public ExtendedMap() | |
{ | |
} | |
public ExtendedMap(MapSpan region) : base(region) | |
{ | |
} | |
public void OnTap(Position coordinate) | |
{ | |
OnTap(new TapEventArgs { Position = coordinate }); | |
} | |
protected virtual void OnTap(TapEventArgs e) | |
{ | |
var handler = Tap; | |
if (handler != null) handler(this, e); | |
} | |
} | |
public class TapEventArgs : EventArgs | |
{ | |
public Position Position { get; set; } | |
} | |
} |
Android
Em seu projeto android crie a classe “ExtendedMapRenderer.cs”.
Observe que a classe herda de MapRenderer e sobrescreve os métodos: OnMapReady, OnElementChanged. Por último crie o método googleMap_MapClick que será responsável por pegar o click do usuário.
using Android.Gms.Maps; | |
using PinClickDemo; | |
using PinClickDemo.Droid; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Maps; | |
using Xamarin.Forms.Maps.Android; | |
using Xamarin.Forms.Platform.Android; | |
[assembly: ExportRenderer(typeof(ExtendedMap), typeof(ExtendedMapRenderer))] | |
namespace PinClickDemo.Droid | |
{ | |
public class ExtendedMapRenderer : MapRenderer, IOnMapReadyCallback | |
{ | |
private GoogleMap _map; | |
public ExtendedMapRenderer() | |
{ | |
} | |
protected override void OnMapReady(GoogleMap googleMap) | |
{ | |
_map = googleMap; | |
if (_map != null) | |
{ | |
_map.MapClick += googleMap_MapClick; | |
} | |
} | |
protected override void OnElementChanged(ElementChangedEventArgs<Map> e) | |
{ | |
if (_map != null) | |
{ | |
_map.MapClick -= googleMap_MapClick; | |
} | |
base.OnElementChanged(e); | |
if (Control != null) | |
((MapView)Control).GetMapAsync(this); | |
} | |
private void googleMap_MapClick(object sender, GoogleMap.MapClickEventArgs e) | |
{ | |
((ExtendedMap)Element).OnTap(new Position(e.Point.Latitude, e.Point.Longitude)); | |
} | |
} | |
} |
iOS
Em seu projeto iOS também crie a classe “ExtendedMapRenderer.cs” herdando de MapRenderer como demonstrado a seguir.
using MapKit; | |
using PinClickDemo; | |
using PinClickDemo.iOS; | |
using UIKit; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Maps; | |
using Xamarin.Forms.Maps.iOS; | |
using Xamarin.Forms.Platform.iOS; | |
[assembly: ExportRenderer(typeof(ExtendedMap), typeof(ExtendedMapRenderer))] | |
namespace PinClickDemo.iOS | |
{ | |
public class ExtendedMapRenderer : MapRenderer | |
{ | |
private readonly UITapGestureRecognizer _tapRecogniser; | |
public ExtendedMapRenderer() | |
{ | |
_tapRecogniser = new UITapGestureRecognizer(OnTap) | |
{ | |
NumberOfTapsRequired = 1, | |
NumberOfTouchesRequired = 1 | |
}; | |
} | |
private void OnTap(UITapGestureRecognizer recognizer) | |
{ | |
var cgPoint = recognizer.LocationInView(Control); | |
var location = ((MKMapView)Control).ConvertPoint(cgPoint, Control); | |
((ExtendedMap)Element).OnTap(new Position(location.Latitude, location.Longitude)); | |
} | |
protected override void OnElementChanged(ElementChangedEventArgs<View> e) | |
{ | |
if (Control != null) | |
Control.RemoveGestureRecognizer(_tapRecogniser); | |
base.OnElementChanged(e); | |
if (Control != null) | |
Control.AddGestureRecognizer(_tapRecogniser); | |
} | |
} | |
} |
Xaml
No arquivo xaml crie um ExtendedMap.
<?xml version="1.0" encoding="utf-8" ?> | |
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" | |
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | |
xmlns:local="clr-namespace:PinClickDemo" | |
x:Class="PinClickDemo.MainPage"> | |
<StackLayout> | |
<local:ExtendedMap x:Name="Mapa" Tap="Mapa_OnTap"/> | |
</StackLayout> | |
</ContentPage> |
CODE-BEHIND
No construtor utilize o MoveToRegion para definir qual a região do mapa que deseja mostrar ao carregar a pagina.
Crie também o método Mapa_OnTap que será responsável por adicionar o pin na lista de pins do maps.
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Maps; | |
namespace PinClickDemo | |
{ | |
public partial class MainPage : ContentPage | |
{ | |
public MainPage() | |
{ | |
InitializeComponent(); | |
Mapa.MoveToRegion(MapSpan.FromCenterAndRadius( | |
new Position(–23.4859591, –47.4420192), | |
Distance.FromMiles(0.5))); | |
} | |
private void Mapa_OnTap(object sender, TapEventArgs e) | |
{ | |
var pin = new Pin | |
{ | |
Type = PinType.Place, | |
Position = e.Position, | |
Label = "Cliked", | |
Address = e.Position.Latitude + " X " + e.Position.Latitude, | |
}; | |
Mapa.Pins.Add(pin); | |
} | |
} | |
} |
Resultado
Android
iOS
Esse e todos os exemplos deste blog encontram-se disponíveis no GitHub.
parabéns pelo post… e pela iniciativa do blog, tá muito bacana!
CurtirCurtido por 1 pessoa
Obrigado José Valente 😀
CurtirCurtir
Como faço pra adicionar mais controles ao mapa? Ex: Zoom, Compass, etc…
CurtirCurtir
Opa, consegui acrescentando, no método OnMapReady do Android, o seguinte trecho de código:
_map.UiSettings.ZoomControlsEnabled = true;
_map.UiSettings.CompassEnabled = true;
Esta é a maneira mais correta de fazer? E como fica pro iOS?
CurtirCurtir