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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
… | |
<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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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