Compartilhar via


Xamarin.Forms Pinos de mapa

O controle Xamarin.FormsMap 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 sua janela de informações, no iOS e Android

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.
  • Position, do tipo Position, 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="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps">
     <maps:Map x:Name="map"
               IsShowingUser="True"
               MoveToLastRegionOnLayoutChange="False">
         <x:Arguments>
             <maps:MapSpan>
                 <x:Arguments>
                     <maps:Position>
                         <x:Arguments>
                             <x:Double>36.9628066</x:Double>
                             <x:Double>-122.0194722</x:Double>
                         </x:Arguments>
                     </maps:Position>
                     <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.Position>
                     <maps:Position>
                         <x:Arguments>
                             <x:Double>36.9628066</x:Double>
                             <x:Double>-122.0194722</x:Double>
                         </x:Arguments>
                     </maps:Position>
                 </maps:Pin.Position>
             </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 Position, 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 Position dele. Para obter informações sobre o Position struct, consulte Mapear posiçã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 Passando argumentos em XAML.

Este é o código C# equivalente:

using Xamarin.Forms.Maps;
// ...
Map map = new Map
{
  // ...
};
Pin pin = new Pin
{
  Label = "Santa Cruz",
  Address = "The city with a boardwalk",
  Type = PinType.Place,
  Position = new Position(36.9628066, -122.0194722)
};
map.Pins.Add(pin);

Aviso

A falha ao definir a Pin.Label propriedade resultará em um ArgumentException lançamento quando o Pin for adicionado a um Map.

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

Captura de tela de um alfinete de mapa, no iOS e Android

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 sua janela de informações, no iOS e Android

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 Xamarin.Forms.Maps;
// ...
Pin boardwalkPin = new Pin
{
    Position = new Position(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
{
    Position = new Position(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ê deve criar um renderizador personalizado para personalizar a aparência do pino. Para obter mais informações, consulte Personalizando um alfinete de mapa.

Exibir uma coleção de marcadores

A classe Map define as seguintes propriedades:

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="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
             x:Class="WorkingWithMaps.PinItemsSourcePage">
    <Grid>
        ...
        <maps:Map x:Name="map"
                  ItemsSource="{Binding Locations}">
            <maps:Map.ItemTemplate>
                <DataTemplate>
                    <maps:Pin Position="{Binding Position}"
                              Address="{Binding Address}"
                              Label="{Binding Description}" />
                </DataTemplate>
            </maps:Map.ItemTemplate>
        </maps:Map>
        ...
    </Grid>
</ContentPage>

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

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.

As capturas de tela a seguir mostram a exibição de Map uma Pin coleção usando a associação de dados:

Captura de tela do mapa com pinos vinculados a dados, no iOS e Android

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:local="clr-namespace:WorkingWithMaps"
             xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps">
    <ContentPage.Resources>
        <local:MapItemTemplateSelector x:Key="MapItemTemplateSelector">
            <local:MapItemTemplateSelector.DefaultTemplate>
                <DataTemplate>
                    <maps:Pin Position="{Binding Position}"
                              Address="{Binding Address}"
                              Label="{Binding Description}" />
                </DataTemplate>
            </local:MapItemTemplateSelector.DefaultTemplate>
            <local:MapItemTemplateSelector.XamarinTemplate>
                <DataTemplate>
                    <!-- Change the property values, or the properties that are bound to. -->
                    <maps:Pin Position="{Binding Position}"
                              Address="{Binding Address}"
                              Label="Xamarin!" />
                </DataTemplate>
            </local:MapItemTemplateSelector.XamarinTemplate>    
        </local:MapItemTemplateSelector>
    </ContentPage.Resources>

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

O exemplo a seguir mostra a classe MapItemTemplateSelector:

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

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

A MapItemTemplateSelector classe define propriedades DefaultTemplate e XamarinTemplate DataTemplate que são configuradas para diferentes modelos de dados. O método OnSelectTemplate retorna o XamarinTemplate, 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 de Pin subclasse a propriedades diferentes, com base no Pin subtipo.

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