Compartilhar via


Mapeamento

Procurar amostra. Procurar no exemplo

O controle .NET MAUI (.NET Multi-Platform App UI) Map é uma exibição multiplataforma para exibir e anotar mapas. O controle Map usa o controle de mapa nativo em cada plataforma e é fornecido pelo pacote NuGet Microsoft.Maui.Controls.Maps.

Importante

O controle Map não é compatível com o Windows devido à falta de um controle de mapa no WinUI. No entanto, o pacote NuGet CommunityToolkit.Maui.Maps fornece acesso ao Bing Mapas por meio de um WebView no Windows. Para obter mais informações, consulte Introdução.

Instalação

O controle Map usa o controle de mapa nativo em cada plataforma. Isso fornece uma experiência de mapas rápida e familiar para os usuários, mas significa que algumas etapas de configuração são necessárias para aderir aos requisitos de API de cada plataforma.

Inicialização do Mapa

O controle Map é fornecido pelo pacote NuGet Microsoft.Maui.Controls.Maps, que deve ser adicionado ao seu projeto de aplicativo do .NET MAUI.

Depois de instalar o pacote NuGet, ele precisa ser inicializado em seu aplicativo chamando o método UseMauiMap no objeto MauiAppBuilder no método CreateMauiApp de sua classe MauiProgram:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            })
            .UseMauiMaps();

        return builder.Build();
    }
}

Depois que o pacote NuGet tiver sido adicionado e inicializado, as APIs Map poderão ser usadas em seu projeto.

Configuração da plataforma

Para que o mapa seja exibido, é necessário realizar configuração adicional no Android. Além disso, no iOS, Android e Mac Catalyst, acessar a localização do usuário requer que permissões de localização tenham sido concedidas ao seu aplicativo.

Catalisador para iOS e Mac

Exibir e interagir com um mapa no iOS e no Mac Catalyst não requer nenhuma configuração adicional. No entanto, para acessar os serviços de localização, você deve definir as solicitações de serviços de localização necessárias em Info.plist. Normalmente, eles serão um ou mais dos seguintes:

Para obter mais informações, confira Escolher a autorização de serviços de localização a ser solicitada em developer.apple.com.

A representação XML para essas chaves em Info.plist é mostrada abaixo. Você deve atualizar os valores de string para refletir como seu aplicativo está usando as informações de localização:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Can we use your location at all times?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location when your app is being used?</string>

Um prompt é exibido quando seu aplicativo tenta acessar a localização do usuário, solicitando acesso:

Captura de tela da solicitação de permissão de localização no iOS.

Android

O processo de configuração para exibir e interagir com um mapa no Android é:

  1. Obter uma chave de API do Google Maps e adicioná-la ao manifesto do aplicativo.
  2. Especifique o número de versão dos serviços do Google Play no manifesto.
  3. [opcional] Especifique permissões de local no manifesto.
  4. [opcional] Especifique a permissão WRITE_EXTERNAL_STORAGE no manifesto.
Obter uma chave da API do Google Maps

Para usar o controle Map no Android, você precisa gerar uma chave de API, que será consumida pelo SDK do Google Maps no qual o controle Map depende do Android. Para fazer isso, siga as instruções em Configurar no Console do Google Cloud e Usar chaves de API em developers.google.com.

Depois que você obtiver uma chave de API, ela precisará ser adicionada no elemento <application> do arquivo Platforms/Android/AndroidManifest.xml, especificando-a como o valor dos metadados com.google.android.geo.API_KEY:

<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true">
  <meta-data android:name="com.google.android.geo.API_KEY" android:value="PASTE-YOUR-API-KEY-HERE" />
</application>

Isso insere a chave de API no manifesto. Sem uma chave de API válida, o controle Map exibirá uma grade em branco.

Observação

com.google.android.geo.API_KEY é o nome de metadados recomendado para a chave de API. Uma chave com esse nome pode ser usada para autenticar em várias APIs baseadas no Google Maps no Android. Para compatibilidade com versões anteriores, o nome dos metadados com.google.android.maps.v2.API_KEY pode ser usado, mas só permite a autenticação para a API v2 do Android Maps. Um aplicativo só pode especificar um dos nomes de metadados da chave de API.

Especificar o número de versão dos serviços do Google Play

Adicione a seguinte declaração no elemento <application> de AndroidManifest.xml:

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

Isso insere no manifesto a versão dos serviços do Google Play com os quais o aplicativo foi compilado.

Especificar permissões de localização

Se o aplicativo precisar acessar a localização do usuário, você precisará solicitar permissão adicionando as permissões ACCESS_COARSE_LOCATION ou ACCESS_FINE_LOCATION (ou ambas) ao manifesto, como um filho do elemento <manifest>:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  ...
  <!-- Required to access the user's location -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>

A permissão ACCESS_COARSE_LOCATION permite que a API use Wi-Fi ou dados móveis, ou ambos, para determinar a localização do dispositivo. As permissões ACCESS_FINE_LOCATION permitem que a API use o GPS (Sistema de Posicionamento Global), Wi-Fi ou dados móveis para determinar uma localização com o máximo possível de precisão.

Um prompt é exibido quando seu aplicativo tenta acessar a localização do usuário, solicitando acesso:

Captura de tela da solicitação de permissão de localização no Android.

Como alternativa, essas permissões podem ser habilitadas no editor de manifesto do Android do Visual Studio.

Especificar a permissão WRITE_EXTERNAL_STORAGE

Se o aplicativo for destinado à API 22 ou inferior, será necessário adicionar a permissão WRITE_EXTERNAL_STORAGE ao manifesto, como um filho do elemento <manifest>:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Isso não será necessário se o aplicativo for direcionado à API 23 ou superior.

Controle de mapeamento

A classe Map define as seguintes propriedades que controlam a aparência e o comportamento do mapa:

  • IsShowingUser, do tipo bool, indica se o mapa está mostrando a localização atual do usuário.
  • ItemsSource, do tipo IEnumerable, que especifica a coleção de itens de alfinete IEnumerable a serem exibidos.
  • ItemTemplate, do tipo DataTemplate, que especifica o DataTemplate a ser aplicado a cada item na coleção de alfinetes exibidos.
  • ItemTemplateSelector, do tipo DataTemplateSelector, que especifica o DataTemplateSelector que será usado para escolher um DataTemplate para um alfinete em runtime.
  • IsScrollEnabled, do tipo bool, determina se o mapa tem permissão para rolar.
  • IsTrafficEnabled, do tipo bool, indica se os dados de tráfego são sobrepostos no mapa.
  • IsZoomEnabled, do tipo bool, determina se o mapa tem permissão para ampliar.
  • MapElements, do tipo IList<MapElement>, representa a lista de elementos no mapa, como polígonos e polilinhas.
  • MapType, do tipo MapType, indica o estilo de exibição do mapa.
  • Pins, do tipo IList<Pin>, representa a lista de alfinetes no mapa.
  • VisibleRegion, do tipo MapSpan, retorna a região do mapa exibida no momento.

Essas propriedades, com exceção das propriedades MapElements, Pins e VisibleRegion, são apoiadas por objetos BindableProperty, o que significa que elas podem ser destinos de associações de dados.

A classe Map também define um evento MapClicked que é disparado quando o mapa é tocado. O objeto MapClickedEventArgs que acompanha o evento tem apenas uma propriedade chamada Location, do tipo Location. Quando o evento é disparado, a propriedade Location é definida como o local do mapa que foi tocado. Para obter informações sobre a classe Location, consulte Localização e distância.

Para obter informações sobre as propriedades ItemsSource, ItemTemplate e ItemTemplateSelector, consulte Exibir uma coleção de alfinetes.

Exibir um mapa

Um Map pode ser exibido adicionando-o a um layout ou página:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps">
    <maps:Map x:Name="map" />
</ContentPage>

Este é o código C# equivalente:

using Map = Microsoft.Maui.Controls.Maps.Map;

namespace WorkingWithMaps
{
    public class MapTypesPageCode : ContentPage
    {
        public MapTypesPageCode()
        {
            Map map = new Map();
            Content = map;
        }
    }
}

Este exemplo chama o construtor padrão Map, que centraliza o mapa em Maui, Havaí:

Captura de tela do controle de mapa com a localização padrão.

Como alternativa, um argumento MapSpan pode ser passado para um construtor Map para definir o ponto central e o nível de zoom do mapa quando ele é carregado. Para obter mais informações, confira Exibir um local específico em um mapa.

Importante

O .NET MAUI tem dois tipos Map - Microsoft.Maui.Controls.Maps.Map e Microsoft.Maui.ApplicationModel.Map. Como o namespace Microsoft.Maui.ApplicationModel é uma das diretivas global using do .NET MAUI, ao usar o controle Microsoft.Maui.Controls.Maps.Map no código, você terá que qualificar totalmente o uso de Map ou usar um alias usando.

Tipos de mapa

A propriedade Map.MapType pode ser definida como um membro de enumeração MapType para definir o estilo de exibição do mapa. A enumeração MapType define os seguintes membros:

  • Street especifica que um mapa de ruas será exibido.
  • Satellite especifica que um mapa contendo imagens de satélite será exibido.
  • Hybrid especifica que um mapa combinando dados de ruas e de satélite será exibido.

Por padrão, um Map exibirá um mapa de ruas se a propriedade MapType estiver indefinida. Como alternativa, a propriedade MapType pode ser definida como um dos membros da enumeração MapType:

<maps:Map MapType="Satellite" />

Este é o código C# equivalente:

Map map = new Map
{
    MapType = MapType.Satellite
};

Exibir uma localização específica em um mapa

A região de um mapa a ser exibida quando um mapa é carregado pode ser definida passando um argumento MapSpan para o construtor Map:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <x:Arguments>
            <maps:MapSpan>
                <x:Arguments>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>36.9628066</x:Double>
                            <x:Double>-122.0194722</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <x:Double>0.01</x:Double>
                    <x:Double>0.01</x:Double>
                </x:Arguments>
            </maps:MapSpan>
        </x:Arguments>
    </maps:Map>
</ContentPage>

Este é o código C# equivalente:

using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Location location = new Location(36.9628066, -122.0194722);
MapSpan mapSpan = new MapSpan(location, 0.01, 0.01);
Map map = new Map(mapSpan);

Este exemplo cria um objeto Map que mostra a região especificada pelo objeto MapSpan. O objeto MapSpan é centrado na latitude e longitude representadas por um objeto Location, e abrange 0,01 graus de latitude e 0,01 graus de longitude. Para obter informações sobre a classe Location, consulte Localização e distância. Para obter informações sobre como passar argumentos em XAML, confira Passar argumentos em XAML.

O resultado é que, quando o mapa é exibido, ele é centralizado em um local específico e abrange um número específico de graus de latitude e longitude:

Captura de tela do controle de mapa com o local especificado.

Criar um objeto MapSpan

Há uma série de abordagens para a criação de objetos MapSpan. Uma abordagem comum é fornecer os argumentos necessários ao construtor MapSpan. Estes são uma latitude e longitude representadas por um objeto Location, e valores double que representam os graus de latitude e longitude que são estendidos pelo MapSpan. Para obter informações sobre a classe Location, consulte Localização e distância.

Como alternativa, há três métodos na classe MapSpan que retornam novos objetos MapSpan:

  1. ClampLatitude retorna um MapSpan com o mesmo LongitudeDegrees que a instância de classe do método e um raio definido pelos argumentos north e south dele.
  2. FromCenterAndRadius retorna um MapSpan que é definido pelos argumentos Location e Distance dele.
  3. WithZoom retorna um MapSpan com o mesmo centro que a instância de classe do método, mas com um raio multiplicado pelo argumento double dele.

Para obter informações sobre o struct Distance, consulte Localização e distância.

Depois que um MapSpan tiver sido criado, as seguintes propriedades podem ser acessadas para recuperar dados sobre ele:

  • Center, do tipo Location, que representa o local no centro geográfico do MapSpan.
  • LatitudeDegrees, do tipo double, que representa os graus de latitude que são abrangidos pelo MapSpan.
  • LongitudeDegrees, do tipo double, que representa os graus de longitude que são abrangidos pelo MapSpan.
  • Radius, do tipo Distance, que representa o raio de MapSpan.

Mover o mapa

O método Map.MoveToRegion pode ser chamado para alterar a posição e o nível de zoom de um mapa. Esse método aceita um argumento MapSpan que define a região do mapa a ser exibida e seu nível de zoom.

O seguinte código mostra um exemplo de como mover a região exibida em um mapa:

using Microsoft.Maui.Maps;
using Microsoft.Maui.Controls.Maps.Map;
...

MapSpan mapSpan = MapSpan.FromCenterAndRadius(location, Distance.FromKilometers(0.444));
map.MoveToRegion(mapSpan);

Ampliar o mapa

O nível de zoom de um Map pode ser alterado sem alterar a localização dele. Isso pode ser feito usando a interface do usuário do mapa ou programaticamente, chamando o método MoveToRegion com um argumento MapSpan que usa o local atual como argumento Location:

double zoomLevel = 0.5;
double latlongDegrees = 360 / (Math.Pow(2, zoomLevel));
if (map.VisibleRegion != null)
{
    map.MoveToRegion(new MapSpan(map.VisibleRegion.Center, latlongDegrees, latlongDegrees));
}

Neste exemplo, o método MoveToRegion é chamado com um argumento MapSpan, que especifica o local atual do mapa por meio da propriedade Map.VisibleRegion, e o nível de zoom como graus de latitude e longitude. O resultado geral é que o nível de zoom do mapa é alterado, mas a localização dele não. Uma abordagem alternativa para implementar o zoom em um mapa é usar o método MapSpan.WithZoom para controlar o fator de zoom.

Importante

Ampliar um mapa, seja por meio da interface do usuário do mapa ou programaticamente, requer que a propriedade Map.IsZoomEnabled seja true. Para obter mais informações sobre essa propriedade, confira Desabilitar zoom.

Personalizar o comportamento do mapa

O comportamento de um Map pode ser personalizado definindo algumas de suas propriedades e manipulando o evento MapClicked.

Observação

Uma personalização adicional do comportamento de mapa pode ser obtida personalizando o manipulador dele. Para obter mais informações, confira Personalizar controles com manipuladores.

Mostrar dados de tráfego

A classe Map define uma propriedade IsTrafficEnabled do tipo bool. Por padrão, essa propriedade é false, o que indica que os dados de tráfego não serão sobrepostos no mapa. Quando essa propriedade é definida como true, os dados de tráfego são sobrepostos no mapa:

<maps:Map IsTrafficEnabled="true" />

Este é o código C# equivalente:

Map map = new Map
{
    IsTrafficEnabled = true
};

Desativar rolagem

A classe Map define uma propriedade IsScrollEnabled do tipo bool. Por padrão, essa propriedade é true, o que indica que o mapa permite rolagem. Quando essa propriedade é definida como false, o mapa não tem rolagem:

<maps:Map IsScrollEnabled="false" />

Este é o código C# equivalente:

Map map = new Map
{
    IsScrollEnabled = false
};

Desabilitar zoom

A classe Map define uma propriedade IsZoomEnabled do tipo bool. Por padrão, essa propriedade é true, o que indica que o zoom pode ser executado no mapa. Quando essa propriedade é definida como false, o mapa não pode ser ampliado ou reduzido:

<maps:Map IsZoomEnabled="false" />

Este é o código C# equivalente:

Map map = new Map
{
    IsZoomEnabled = false
};

Detectar a localização do usuário

A classe Map define uma propriedade IsShowingUser do tipo bool. Por padrão, essa propriedade é false, que indica que o mapa não está mostrando a localização atual do usuário. Quando essa propriedade é definida como true, o mapa mostra a localização atual do usuário:

<maps:Map IsShowingUser="true" />

Este é o código C# equivalente:

Map map = new Map
{
    IsShowingUser = true
};

Importante

Acessar a localização do usuário requer que permissões de localização tenham sido concedidas ao aplicativo. Para obter mais informações, confira Configuração da plataforma.

Cliques no mapa

A classe Map define um evento MapClicked que é acionado quando o mapa é tocado. O objeto MapClickedEventArgs que acompanha o evento tem apenas uma propriedade chamada Location, do tipo Location. Quando o evento é disparado, a propriedade Location é definida como o local do mapa que foi tocado. Para obter informações sobre a classe Location, consulte Localização e distância.

O seguinte exemplo de código mostra um manipulador de eventos para o evento MapClicked:

void OnMapClicked(object sender, MapClickedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine($"MapClick: {e.Location.Latitude}, {e.Location.Longitude}");
}

Neste exemplo, o manipulador de eventos OnMapClicked gera a latitude e a longitude que representam o local do mapa tocado. O manipulador de eventos precisa ser registrado com o evento MapClicked:

<maps:Map MapClicked="OnMapClicked" />

Este é o código C# equivalente:

Map map = new Map();
map.MapClicked += OnMapClicked;

Localização e distância

O namespace Microsoft.Maui.Devices.Sensors contém uma classe Location que normalmente é usada ao posicionar um mapa e seus alfinetes. O namespace Microsoft.Maui.Maps contém um struct Distance que pode ser usado opcionalmente ao posicionar um mapa.

Localidade

A classe Location encapsula um local armazenado como valores de latitude e longitude. Essa classe define as seguintes propriedades:

  • Accuracy, do tipo double?, que representa a precisão horizontal do Location, em metros.
  • Altitude, do tipo double?, que representa a altitude em metros em um sistema de referência especificado pela propriedade AltitudeReferenceSystem.
  • AltitudeReferenceSystem, do tipo AltitudeReferenceSystem, que especifica o sistema de referência no qual o valor de altitude é fornecido.
  • Course, do tipo double?, que indica o valor de graus relativo ao norte verdadeiro.
  • IsFromMockProvider, do tipo bool, que indica se o local é do GPS ou de um provedor de localização fictício.
  • Latitude, do tipo double, que representa a latitude do local em graus decimais.
  • Longitude, do tipo double, que representa a longitude do local em graus decimais.
  • Speed, do tipo double?, que representa a velocidade em metros por segundo.
  • Timestamp, do tipo DateTimeOffset, que representa o carimbo de data/hora quando o Location foi criado.
  • VerticalAccuracy, do tipo double?, que especifica a precisão vertical do Location, em metros.

Os objetos Location são criados com uma das sobrecargas do construtor Location, que normalmente exigem argumentos mínimos de latitude e longitude especificados como valores double:

Location location = new Location(36.9628066, -122.0194722);

Ao criar um objeto Location, o valor de latitude será fixado entre -90,0 e 90,0, e o valor de longitude será fixado entre -180,0 e 180,0.

Observação

A classe GeographyUtils tem um método de extensão ToRadians que converte um valor double de graus em radianos e um método de extensão ToDegrees que converte um valor double de radianos em graus.

A classe Location também tem métodos CalculateDistance que calculam a distância entre dois locais.

Distância

O struct Distance encapsula uma distância armazenada como um valor double, que representa a distância em metros. Esse struct define três propriedades somente leitura:

  • Kilometers, do tipo double, que representa a distância em quilômetros que é abrangida pelo Distance.
  • Meters, do tipo double, que representa a distância em metros que é abrangida pelo Distance.
  • Miles, do tipo double, que representa a distância em milhas que é abrangida pelo Distance.

Os objetos Distance podem ser criados com o construtor Distance, que requer um argumento de metros especificado como um double:

Distance distance = new Distance(1450.5);

Como alternativa, os objetos Distance podem ser criados com os métodos de fábrica FromKilometers, FromMeters, FromMiles e BetweenPositions:

Distance distance1 = Distance.FromKilometers(1.45); // argument represents the number of kilometers
Distance distance2 = Distance.FromMeters(1450.5);   // argument represents the number of meters
Distance distance3 = Distance.FromMiles(0.969);     // argument represents the number of miles
Distance distance4 = Distance.BetweenPositions(location1, location2);

marcadores

O controle Map permite que os locais sejam marcados com objetos Pin. Um Pin é um marcador de mapa que abre uma janela de informações quando tocado:

Captura de tela de um alfinete de mapa e a respectiva janela de informações.

Quando um objeto Pin é adicionado à coleção Map.Pins, o alfinete é renderizado no mapa.

A classe Pin tem as propriedades a seguir:

  • Address, do tipo string, que normalmente representa o endereço da localização do alfinete. No entanto, isso pode ser qualquer conteúdo string, não apenas um endereço.
  • Label, do tipo string, que normalmente representa o título do alfinete.
  • Location, do tipo Location, que representa a latitude e longitude do alfinete.
  • Type, do tipo PinType, que representa o tipo de alfinete.

Essas propriedades são apoiadas por objetos BindableProperty, o que significa que um Pin pode ser alvo de associações de dados. Para obter mais informações sobre objetos Pin de vinculação de dados, consulte Exibir uma coleção de alfinetes.

Além disso, a classe Pin define eventos MarkerClicked e InfoWindowClicked. O evento MarkerClicked é disparado quando um alfinete é tocado e o evento InfoWindowClicked é disparado quando a janela de informações é tocada. O objeto PinClickedEventArgs que acompanha ambos os eventos tem apenas uma propriedade HideInfoWindow, do tipo bool.

Exibir um alfinete

Um Pin pode ser adicionado a um Map em XAML:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map x:Name="map">
        <x:Arguments>
            <maps:MapSpan>
                <x:Arguments>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>36.9628066</x:Double>
                            <x:Double>-122.0194722</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <x:Double>0.01</x:Double>
                    <x:Double>0.01</x:Double>
                </x:Arguments>
            </maps:MapSpan>
        </x:Arguments>
        <maps:Map.Pins>
            <maps:Pin Label="Santa Cruz"
                      Address="The city with a boardwalk"
                      Type="Place">
                <maps:Pin.Location>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>36.9628066</x:Double>
                            <x:Double>-122.0194722</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                </maps:Pin.Location>
            </maps:Pin>
        </maps:Map.Pins>
    </maps:Map>
</ContentPage>

Esse XAML cria um objeto Map que mostra a região especificada pelo objeto MapSpan. O objeto MapSpan é centrado na latitude e longitude representadas por um objeto Location, que se estende 0,01 graus de latitude e longitude. Um objeto Pin é adicionado à coleção Map.Pins e desenhado no Map no local especificado pela propriedade Location dele. Para obter informações sobre a classe Location, consulte Localização e distância. Para obter informações sobre como passar argumentos em XAML para objetos que não têm construtores padrão, consulte Passar argumentos em XAML.

Este é o código C# equivalente:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Map map = new Map
{
  ...
};

Pin pin = new Pin
{
  Label = "Santa Cruz",
  Address = "The city with a boardwalk",
  Type = PinType.Place,
  Location = new Location(36.9628066, -122.0194722)
};
map.Pins.Add(pin);

Este código de exemplo resulta em apenas um alfinete sendo renderizado em um mapa:

Captura de tela de um alfinete do mapa.

Interagir com um alfinete

Por padrão, quando um Pin é tocado, a janela de informações dele é exibida:

Captura de tela de um alfinete de mapa e a respectiva janela de informações.

Tocar em outro lugar no mapa fecha a janela de informações.

A classe Pin define um evento MarkerClicked, que é acionado quando um Pin é tocado. Não é necessário manipular esse evento para exibir a janela de informações. Em vez disso, esse evento deverá ser manipulado quando houver um requisito para ser notificado de que um alfinete específico foi tocado.

A classe Pin também define um evento InfoWindowClicked que é acionado quando uma janela de informações é tocada. Esse evento deverá ser manipulado quando houver um requisito para ser notificado de que uma janela de informações específica foi tocada.

O seguinte código mostra um exemplo de manipulação desses eventos:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Pin boardwalkPin = new Pin
{
    Location = new Location(36.9641949, -122.0177232),
    Label = "Boardwalk",
    Address = "Santa Cruz",
    Type = PinType.Place
};
boardwalkPin.MarkerClicked += async (s, args) =>
{
    args.HideInfoWindow = true;
    string pinName = ((Pin)s).Label;
    await DisplayAlert("Pin Clicked", $"{pinName} was clicked.", "Ok");
};

Pin wharfPin = new Pin
{
    Location = new Location(36.9571571, -122.0173544),
    Label = "Wharf",
    Address = "Santa Cruz",
    Type = PinType.Place
};
wharfPin.InfoWindowClicked += async (s, args) =>
{
    string pinName = ((Pin)s).Label;
    await DisplayAlert("Info Window Clicked", $"The info window was clicked for {pinName}.", "Ok");
};

O objeto PinClickedEventArgs que acompanha ambos os eventos tem apenas uma propriedade HideInfoWindow, do tipo bool. Quando essa propriedade é definida como true dentro de um manipulador de eventos, a janela de informações é ocultada.

Tipos de alfinete

Os objetos Pin incluem uma propriedade Type, do tipo PinType, que representa o tipo de alfinete. A enumeração PinType define os seguintes membros:

  • Generic, que representa um alfinete genérico.
  • Place, que representa um alfinete para um lugar.
  • SavedPin, que representa um alfinete para um local salvo.
  • SearchResult, que representa um alfinete para um resultado de pesquisa.

No entanto, definir a propriedade Pin.Type como qualquer membro PinType não altera a aparência do alfinete renderizado. Em vez disso, você precisa personalizar o manipulador Pin para personalizar a aparência do alfinete. Para obter mais informações sobre a personalização do manipulador, consulte Personalizar controles com manipuladores.

Exibir uma coleção de marcadores

A classe Map define as seguintes propriedades associáveis:

  • ItemsSource, do tipo IEnumerable, que especifica a coleção de itens de alfinete IEnumerable a serem exibidos.
  • ItemTemplate, do tipo DataTemplate, que especifica o DataTemplate a ser aplicado a cada item na coleção de alfinetes exibidos.
  • ItemTemplateSelector, do tipo DataTemplateSelector, que especifica o DataTemplateSelector que será usado para escolher um DataTemplate para um alfinete em runtime.

Importante

A propriedade ItemTemplate tem precedência quando as propriedades ItemTemplate e ItemTemplateSelector estão definidas.

Um Map pode ser preenchido com alfinetes usando a associação de dados para associar sua propriedade ItemsSource a uma coleção IEnumerable:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps">    
    <Grid>
        ...
        <maps:Map x:Name="map"
                  ItemsSource="{Binding Positions}">
            <maps:Map.ItemTemplate>
                <DataTemplate>
                    <maps:Pin Location="{Binding Location}"
                              Address="{Binding Address}"
                              Label="{Binding Description}" />
                </DataTemplate>    
            </maps:Map.ItemTemplate>
        </maps:Map>
        ...
    </Grid>
</ContentPage>

Os dados da propriedade ItemsSource se vinculam à propriedade Positions do modelo de exibição conectado, que retorna um ObservableCollection de objetos Position, que é um tipo personalizado. Cada objeto Position define propriedades Address e Description, do tipo string, e uma propriedade Location, do tipo Location.

A aparência de cada item na coleção IEnumerable é definida configurando-se a propriedade ItemTemplate como um DataTemplate que contém um objeto Pin, cujos dados são associados às propriedades adequadas.

A seguinte captura de tela mostra um Map exibindo uma coleção Pin usando a associação de dados:

Captura de tela do mapa com alfinetes associados a dados.

Escolher a aparência do item em tempo de execução

A aparência de cada item na coleção IEnumerable pode ser escolhida em tempo de execução, com base no valor do item, definindo a propriedade ItemTemplateSelector como DataTemplateSelector:

<ContentPage ...
             xmlns:templates="clr-namespace:WorkingWithMaps.Templates"
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps">
    <ContentPage.Resources>
       <templates:MapItemTemplateSelector x:Key="MapItemTemplateSelector">
           <templates:MapItemTemplateSelector.DefaultTemplate>
               <DataTemplate>
                   <maps:Pin Location="{Binding Location}"
                             Address="{Binding Address}"
                             Label="{Binding Description}" />
               </DataTemplate>
           </templates:MapItemTemplateSelector.DefaultTemplate>
           <templates:MapItemTemplateSelector.SanFranTemplate>
               <DataTemplate>
                   <maps:Pin Location="{Binding Location}"
                             Address="{Binding Address}"
                             Label="Xamarin!" />
               </DataTemplate>
           </templates:MapItemTemplateSelector.SanFranTemplate>    
       </templates:MapItemTemplateSelector>
    </ContentPage.Resources>

    <Grid>
        ...
        <maps:Map x:Name="map"
                  ItemsSource="{Binding Positions}"
                  ItemTemplateSelector="{StaticResource MapItemTemplateSelector}">
        ...
    </Grid>
</ContentPage>

O exemplo a seguir mostra a classe MapItemTemplateSelector:

using WorkingWithMaps.Models;

namespace WorkingWithMaps.Templates;

public class MapItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate SanFranTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return ((Position)item).Address.Contains("San Francisco") ? SanFranTemplate : DefaultTemplate;
    }
}

A classe MapItemTemplateSelector define as propriedades DefaultTemplate e SanFranTemplate do DataTemplate como modelos de dados diferentes. O método OnSelectTemplate retorna o SanFranTemplate, que exibe "Xamarin" como um rótulo quando um Pin é tocado, quando o item tem um endereço que contém "San Francisco". Quando o item não tem um endereço que contém "São Francisco", o método OnSelectTemplate retorna o DefaultTemplate.

Observação

Um caso de uso para essa funcionalidade é associar propriedades de objetos Pin com subclasse a propriedades diferentes, com base no subtipo Pin.

Para obter mais informações sobre seletores de modelo de dados, consulte Criar um DataTemplateSelector.

Polígonos, polilinhas e círculos

Os elementos Polygon, Polyline e Circle permitem realçar áreas específicas em um mapa. Uma Polygon é uma forma totalmente fechada que pode ter um traçado e uma cor de preenchimento. Uma Polyline é uma linha que não abrange totalmente uma área. Uma Circle destaca uma área circular do mapa:

Polígono e polilinha em um mapa.Círculo em um mapa.

As classes Polygon, Polyline e Circle derivam da classe MapElement, que expõe as seguintes propriedades associáveis:

  • StrokeColor é um objeto Color que determina a cor da linha.
  • StrokeWidth é um objeto float que determina a largura da linha.

A classe Polygon define uma propriedade associável adicional:

  • FillColor é um objeto Color que determina a cor da tela de fundo do polígono.

Além disso, as classes Polygon e Polyline definem uma propriedade GeoPath, que é uma lista de objetos Location que especificam os pontos da forma.

A classe Circle define as seguintes propriedades associáveis:

  • Center é um objeto Location que define o centro do círculo, em latitude e longitude.
  • Radius é um objeto Distance que define o raio do círculo em metros, quilômetros ou milhas.
  • FillColor é uma propriedade Color que determina a cor dentro do perímetro do círculo.

Criar um polígono

Um objeto Polygon pode ser adicionado a um mapa instanciando-o e adicionando-o à coleção MapElements do mapa:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <maps:Map.MapElements>
            <maps:Polygon StrokeColor="#FF9900"
                          StrokeWidth="8"
                          FillColor="#88FF9900">
                <maps:Polygon.Geopath>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6458676</x:Double>
                            <x:Double>-122.1356007</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6458097</x:Double>
                            <x:Double>-122.142789</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    ...
                </maps:Polygon.Geopath>
            </maps:Polygon>
        </maps:Map.MapElements>
    </maps:Map>
</ContentPage>

Este é o código C# equivalente:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Map map = new Map();

// Instantiate a polygon
Polygon polygon = new Polygon
{
    StrokeWidth = 8,
    StrokeColor = Color.FromArgb("#1BA1E2"),
    FillColor = Color.FromArgb("#881BA1E2"),
    Geopath =
    {
        new Location(47.6368678, -122.137305),
        new Location(47.6368894, -122.134655),
        ...
    }
};

// Add the polygon to the map's MapElements collection
map.MapElements.Add(polygon);

As propriedades StrokeColor e StrokeWidth são especificadas para definir o contorno do polígono. Neste exemplo, o valor da propriedade FillColor corresponde ao valor da propriedade StrokeColor, mas tem um valor alfa especificado para torná-lo transparente, permitindo que o mapa subjacente fique visível através da forma. A propriedade GeoPath contém uma lista de objetos Location que definem as coordenadas geográficas dos pontos de polígono. Um objeto Polygon é renderizado no mapa depois de ter sido adicionado à coleção MapElements do Map.

Observação

Um Polygon é uma forma totalmente fechada. O primeiro e o último pontos serão automaticamente conectados se não corresponderem.

Criar uma polilinha

Um objeto Polyline pode ser adicionado a um mapa instanciando-o e adicionando-o à coleção MapElements do mapa:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <maps:Map.MapElements>
            <maps:Polyline StrokeColor="Black"
                           StrokeWidth="12">
                <maps:Polyline.Geopath>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6381401</x:Double>
                            <x:Double>-122.1317367</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>47.6381473</x:Double>
                            <x:Double>-122.1350841</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                    ...
                </maps:Polyline.Geopath>
            </maps:Polyline>
        </maps:Map.MapElements>
    </maps:Map>
</ContentPage>

Este é o código C# equivalente:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;
...

Map map = new Map();

// instantiate a polyline
Polyline polyline = new Polyline
{
    StrokeColor = Colors.Blue,
    StrokeWidth = 12,
    Geopath =
    {
        new Location(47.6381401, -122.1317367),
        new Location(47.6381473, -122.1350841),
        ...
    }
};

// Add the Polyline to the map's MapElements collection
map.MapElements.Add(polyline);

As propriedades StrokeColor e StrokeWidth são especificadas para definir a aparência da linha. A propriedade GeoPath contém uma lista de objetos Location que definem as coordenadas geográficas dos pontos de polilinha. Um objeto Polyline é renderizado no mapa depois de ter sido adicionado à coleção MapElements do Map.

Criar um círculo

Um objeto Circle pode ser adicionado a um mapa instanciando-o e adicionando-o à coleção MapElements do mapa:

<ContentPage ...
             xmlns:maps="http://schemas.microsoft.com/dotnet/2021/maui/maps"
             xmlns:sensors="clr-namespace:Microsoft.Maui.Devices.Sensors;assembly=Microsoft.Maui.Essentials">
    <maps:Map>
        <maps:Map.MapElements>
            <maps:Circle StrokeColor="#88FF0000"
                         StrokeWidth="8"
                         FillColor="#88FFC0CB">
                <maps:Circle.Center>
                    <sensors:Location>
                        <x:Arguments>
                            <x:Double>37.79752</x:Double>
                            <x:Double>-122.40183</x:Double>
                        </x:Arguments>
                    </sensors:Location>
                </maps:Circle.Center>
                <maps:Circle.Radius>
                    <maps:Distance>
                        <x:Arguments>
                            <x:Double>250</x:Double>
                        </x:Arguments>
                    </maps:Distance>
                </maps:Circle.Radius>
            </maps:Circle>             
        </maps:Map.MapElements>
    </maps:Map>
</ContentPage>

Este é o código C# equivalente:

using Microsoft.Maui.Controls.Maps;
using Microsoft.Maui.Maps;
using Map = Microsoft.Maui.Controls.Maps.Map;

Map map = new Map();

// Instantiate a Circle
Circle circle = new Circle
{
    Center = new Location(37.79752, -122.40183),
    Radius = new Distance(250),
    StrokeColor = Color.FromArgb("#88FF0000"),
    StrokeWidth = 8,
    FillColor = Color.FromArgb("#88FFC0CB")
};

// Add the Circle to the map's MapElements collection
map.MapElements.Add(circle);

A localização do Circle no Mapa é determinada pelo valor das propriedades Center e Radius. A propriedade Center define o centro do círculo em latitude e longitude, enquanto a propriedade Radius define o raio do círculo em metros. As propriedades StrokeColor e StrokeWidth são especificadas para definir o contorno do círculo. O valor da propriedade FillColor especifica a cor dentro do perímetro do círculo. Neste exemplo, ambos os valores de cor especificam um canal alfa, permitindo que o mapa subjacente fique visível através do círculo. O objeto Circle é renderizado no mapa depois de ter sido adicionado à coleção MapElements do Map.

Observação

A classe GeographyUtils tem um método de extensão ToCircumferencePositions que converte um objeto Circle (que define os valores de propriedade Center e Radius) em uma lista de objetos Location que compõem as coordenadas de latitude e longitude do perímetro do círculo.

Geocodificação e geolocalização

A classe Geocoding, no namespace Microsoft.Maui.Devices.Sensors, pode ser usada para codificar geograficamente uma marca de lugar para coordenadas posicionais e reverter coordenadas de código geográfico em uma marca de lugar. Para obter mais informações, confira Codificação geográfica.

A classe Geolocation, no namespace Microsoft.Maui.Devices.Sensors, fornece APIs para recuperar as coordenadas de geolocalização atuais do dispositivo. Para obter mais informações, confira Geolocalização.

Iniciar o aplicativo de mapa nativo

O aplicativo de mapa nativo em cada plataforma pode ser iniciado a partir de um aplicativo do .NET MAUI pela classe Launcher. Essa classe permite que um aplicativo abra outro aplicativo por meio do respectivo esquema de URI personalizado. A funcionalidade do iniciador pode ser invocada com o método OpenAsync, passando um argumento string ou Uri que representa o esquema de URL personalizado a ser aberto. Para obter mais informações sobre a classe Launcher, consulte Launcher.

Observação

Uma alternativa ao uso da classe Launcher é usar a classe Map do namespace Microsoft.Maui.ApplicationModel. Para obter mais informações, confira Mapa.

O aplicativo de mapas em cada plataforma usa um esquema de URI personalizado exclusivo. Para obter informações sobre o esquema de URI de mapas no iOS, consulte Links de mapa em developer.apple.com. Para obter informações sobre o esquema de URI do Google Maps no Android, consulte o Guia do desenvolvedor do Google Maps e Intenções do Google Maps para Android em developers.android.com. Para obter informações sobre o esquema de URI de mapas no Windows, consulte Iniciar o aplicativo Mapas do Windows.

Iniciar o aplicativo de mapa em uma localização específica

Uma localização no aplicativo de mapas nativo pode ser aberta adicionando parâmetros de consulta apropriados ao esquema de URI personalizado para cada aplicativo de mapa:

if (DeviceInfo.Current.Platform == DevicePlatform.iOS || DeviceInfo.Current.Platform == DevicePlatform.MacCatalyst)
{
    // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
    await Launcher.OpenAsync("http://maps.apple.com/?q=394+Pacific+Ave+San+Francisco+CA");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
    // opens the Maps app directly
    await Launcher.OpenAsync("geo:0,0?q=394+Pacific+Ave+San+Francisco+CA");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.WinUI)
{
    await Launcher.OpenAsync("bingmaps:?where=394 Pacific Ave San Francisco CA");
}

Este código de exemplo resulta no aplicativo de mapa nativo sendo iniciado em cada plataforma, com o mapa centralizado em um alfinete representando a localização especificada.

Iniciar o aplicativo de mapa com direções

O aplicativo de mapas nativos pode ser iniciado exibindo direções, adicionando parâmetros de consulta apropriados ao esquema de URI personalizado para cada aplicativo de mapa:

if (DeviceInfo.Current.Platform == DevicePlatform.iOS || DeviceInfo.Current.Platform == DevicePlatform.MacCatalyst)
{
    // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html
    await Launcher.OpenAsync("http://maps.apple.com/?daddr=San+Francisco,+CA&saddr=cupertino");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
    // opens the 'task chooser' so the user can pick Maps, Chrome or other mapping app
    await Launcher.OpenAsync("http://maps.google.com/?daddr=San+Francisco,+CA&saddr=Mountain+View");
}
else if (DeviceInfo.Current.Platform == DevicePlatform.WinUI)
{
    await Launcher.OpenAsync("bingmaps:?rtp=adr.394 Pacific Ave San Francisco CA~adr.One Microsoft Way Redmond WA 98052");
}

Este código de exemplo resulta no aplicativo de mapa nativo sendo iniciado em cada plataforma, com o mapa centralizado em uma rota entre as localizações especificadas.