Marcadores de mapa de Xamarin.Forms

Download SampleDescargar el ejemplo

El control Xamarin.FormsMap permite marcar ubicaciones con objetos Pin. Pin es un marcador de mapa que abre una ventana de información cuando se pulsa:

Screenshot of a map pin and its information window, on iOS and Android

Cuando se agrega un objeto Pin a la colección Map.Pins, la marca o pin se representa en el mapa.

La clase Pin tiene las siguientes propiedades:

  • Address, de tipo string, que normalmente representa la dirección de la ubicación de la marca o pin. Sin embargo, puede ser cualquier contenido string, no solo una dirección.
  • Label, de tipo string, que normalmente representa el título del pin o marca.
  • Position, de tipo Position, que representa la latitud y la longitud del pin o marca.
  • Type, de tipo PinType, que representa el tipo de pin o marca.

Las propiedades están respaldadas por objetos BindableProperty, lo que significa que un objeto Pin puede ser destino de los enlaces de datos. Para más información sobre los objetos de enlace de datos Pin, consulta Presentación de una colección de pines.

Además, la clase Pin define los eventos MarkerClicked y InfoWindowClicked. El evento MarkerClicked se desencadena cuando se pulsa en una marca y el evento InfoWindowClicked se desencadena cuando se pulsa la ventana de información. El objeto PinClickedEventArgs que acompaña a ambos eventos tiene una propiedad HideInfoWindow, de tipo bool.

Mostrar un pin

Un Pin se puede agregar a Map en 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>

Este XAML crea un objeto Map con el que muestra la región especificada por el objeto MapSpan. El objeto MapSpan se centra en la latitud y la longitud representadas por un objeto Position, que se extiende 0,01 grados de latitud y longitud. Se agrega un objeto Pin a la colección Map.Pins y se dibuja en Map en la ubicación especificada por su propiedad Position. Para obtener información sobre la estructura Position, vea Posición y distancia de mapa. Para obtener información sobre cómo pasar argumentos en XAML a objetos que carecen de constructores predeterminados,vea Transferencia de argumentos en XAML.

El código de C# equivalente es el siguiente:

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);

Advertencia

Si no se establece la propiedad Pin.Label, se iniciará una excepción ArgumentException cuando se agregue Pin a Map.

Como resultado de este código de ejemplo, solo se representa un único pin o marca en un mapa:

Screenshot of a map pin, on iOS and Android

Interacción con un pin

De forma predeterminada, cuando se pulsa en un Pin, aparece la ventana de información:

Screenshot of a map pin and its information window, on iOS and Android

Al pulsar en otro lugar del mapa, se cierra la ventana de información.

La clase Pin define un evento MarkerClicked, que se desencadena cuando se pulsa en un Pin. No es necesario controlar este evento para mostrar la ventana de información. En su lugar, este evento debe usarse cuando hay un requisito para recibir una notificación de que se ha pulsado un pin específico.

La clase Pin también define un evento InfoWindowClicked que se desencadena cuando se pulsa en una ventana de información. Este evento debe usarse cuando se necesita recibir una notificación de que se ha pulsado en una ventana de información específica.

El siguiente código muestra un ejemplo de cómo se gestionan estos 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");
};

El objeto PinClickedEventArgs que acompaña a ambos eventos tiene una propiedad HideInfoWindow, de tipo bool. Cuando esta propiedad se establece en true dentro de un controlador de eventos, la ventana de información se ocultará.

Tipos de pines

Los objetos Pin incluyen una propiedad Type, de tipo PinType, que representa el tipo de pin o marca. La enumeración PinType define los miembros siguientes:

  • Generic representa un pin genérico.
  • Place, representa un pin o marca de un lugar.
  • SavedPin, representa un pin o marca de una ubicación guardada.
  • SearchResult, representa un pin o marca de un resultado de búsqueda.

Aunque establecer la propiedad Pin.Type en cualquier miembro PinType no cambia la apariencia de la marca o pin representado. En su lugar, debe crear un representador personalizado para personalizar la apariencia del marcador. Para más información, vea Personalización de un marcador de mapa.

Presentación de una colección de pin

La clase Map define las propiedades siguientes:

Importante

Si estableces las propiedades ItemTemplate y ItemTemplateSelector, la prioridad la tiene la propiedad ItemTemplate.

Map se puede rellenar con marcadores mediante el enlace de datos para enlazar su propiedad ItemsSource a una colección 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>

Los datos de propiedad ItemsSource se enlazan a la propiedad Locations del modelo de vista conectado, que devuelve ObservableCollection de objetos Location, que es un tipo personalizado. Cada objeto Location define las propiedades Address y Description, de tipo string, y una propiedad Position, de tipo Position.

La apariencia de cada elemento de la colección IEnumerable se define estableciendo la propiedad ItemTemplate en DataTemplate que contiene un objeto Pin que los datos enlazan a las propiedades adecuadas.

En las capturas de pantalla siguientes se muestra un elemento Map que muestra una colección de Pin mediante el enlace de datos:

Screenshot of map with data bound pins, on iOS and Android

Elección de la apariencia del elemento en tiempo de ejecución

La apariencia de cada elemento de la colección IEnumerable se puede elegir en tiempo de ejecución, en función del valor del elemento, estableciendo la propiedad ItemTemplateSelector en 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>

En el ejemplo siguiente se muestra la clase 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;
    }
}

La clase MapItemTemplateSelector define las propiedades DefaultTemplate y XamarinTemplateDataTemplate que se establecen en plantillas de datos diferentes. El método OnSelectTemplate devuelve XamarinTemplate, que muestra “Xamarin” como una etiqueta cuando se pulsa Pin, cuando el elemento tiene una dirección que contiene “San Francisco”. Cuando el elemento no tiene una dirección que contenga “San Francisco”, el método OnSelectTemplate devuelve DefaultTemplate.

Nota:

Un caso de uso de esta funcionalidad es enlazar propiedades de objetos Pin de subclase a diferentes propiedades, en función del subtipo Pin.

Para más información sobre los selectores de plantillas de datos, vea Creación de una instancia de Xamarin.Forms DataTemplateSelector.