Xamarin.Forms Diseño de CollectionView

Download SampleDescargar el ejemplo

CollectionView define las siguientes propiedades que controlan el diseño:

Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos.

De forma predeterminada, CollectionView mostrará sus elementos en una lista vertical. Sin embargo, se puede usar cualquiera de los siguientes diseños:

  • Lista vertical: una lista de una columna que crece verticalmente a medida que se agregan nuevos elementos.
  • Lista horizontal: una lista de una fila que crece horizontalmente a medida que se agregan nuevos elementos.
  • Cuadrícula vertical: una cuadrícula de varias columnas que crece verticalmente a medida que se agregan nuevos elementos.
  • Cuadrícula horizontal: una cuadrícula de varias filas que crece horizontalmente a medida que se agregan nuevos elementos.

Estos diseños se pueden especificar estableciendo la propiedad ItemsLayout en la clase que deriva de la clase ItemsLayout. Esta clase define las propiedades siguientes:

Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos. Para obtener más información sobre los puntos de acoplamiento, vea Puntos de acoplamiento en la guía de desplazamiento de CollectionView Xamarin.Forms.

La enumeración ItemsLayoutOrientation define los miembros siguientes:

  • Vertical indica que CollectionView se expandirá verticalmente a medida que se agregan elementos.
  • Horizontal indica que CollectionView se expandirá horizontalmente a medida que se agregan elementos.

La clase LinearItemsLayout hereda de la clase ItemsLayout y define una propiedad ItemSpacing, de tipo double, que representa el espacio vacío alrededor de cada elemento. El valor predeterminado de esta propiedad es 0 y su valor siempre debe ser mayor o igual que 0. La clase LinearItemsLayout también define los miembros estáticos Vertical y Horizontal. Estos miembros se pueden usar para crear listas verticales u horizontales, respectivamente. Como alternativa, se puede crear un objeto LinearItemsLayout, especificando un miembro de enumeración ItemsLayoutOrientation como argumento.

Además, la clase GridItemsLayout hereda de la clase ItemsLayout y define las siguientes propiedades:

  • VerticalItemSpacing, de tipo double, que representa el espacio vacío vertical alrededor de cada elemento. El valor predeterminado de esta propiedad es 0 y su valor siempre debe ser mayor o igual que 0.
  • HorizontalItemSpacing, de tipo double, que representa el espacio vacío horizontal alrededor de cada elemento. El valor predeterminado de esta propiedad es 0 y su valor siempre debe ser mayor o igual que 0.
  • Span, de tipo int, que representa el número de columnas o filas que se van a mostrar en la cuadrícula. El valor predeterminado de esta propiedad es 1 y su valor siempre debe ser mayor o igual que 1.

Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos.

Nota:

CollectionView usa los motores de diseño nativos para realizar el diseño.

Lista vertical

De forma predeterminada, CollectionView mostrará sus elementos en un diseño de lista vertical. Por lo tanto, no es necesario establecer la propiedad ItemsLayout para usar este diseño:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2"
                       Source="{Binding ImageUrl}"
                       Aspect="AspectFill"
                       HeightRequest="60"
                       WidthRequest="60" />
                <Label Grid.Column="1"
                       Text="{Binding Name}"
                       FontAttributes="Bold" />
                <Label Grid.Row="1"
                       Grid.Column="1"
                       Text="{Binding Location}"
                       FontAttributes="Italic"
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Sin embargo, por integridad, en XAML CollectionView se puede establecer para mostrar sus elementos en una lista vertical estableciendo su propiedad ItemsLayout en VerticalList:

<CollectionView ItemsSource="{Binding Monkeys}"
                ItemsLayout="VerticalList">
    ...
</CollectionView>

Como alternativa, esto también se puede lograr estableciendo la propiedad ItemsLayout en un LinearItemsLayout objeto, especificando el miembro de enumeración VerticalItemsLayoutOrientation como valor de la propiedad Orientation:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Vertical" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemsLayout = LinearItemsLayout.Vertical
};

Esto da como resultado una lista de una sola columna, que crece verticalmente a medida que se agregan nuevos elementos:

Screenshot of a CollectionView vertical list layout, on iOS and Android

Lista horizontal

En XAML, CollectionView puede mostrar sus elementos en una lista horizontal estableciendo su propiedad ItemsLayout en HorizontalList:

<CollectionView ItemsSource="{Binding Monkeys}"
                ItemsLayout="HorizontalList">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="35" />
                    <RowDefinition Height="35" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="140" />
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2"
                       Source="{Binding ImageUrl}"
                       Aspect="AspectFill"
                       HeightRequest="60"
                       WidthRequest="60" />
                <Label Grid.Column="1"
                       Text="{Binding Name}"
                       FontAttributes="Bold"
                       LineBreakMode="TailTruncation" />
                <Label Grid.Row="1"
                       Grid.Column="1"
                       Text="{Binding Location}"
                       LineBreakMode="TailTruncation"
                       FontAttributes="Italic"
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Como alternativa, este diseño también se puede lograr estableciendo la propiedad ItemsLayout en un objeto LinearItemsLayout, especificando el miembro de enumeración HorizontalItemsLayoutOrientation como valor de propiedad Orientation:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Horizontal" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemsLayout = LinearItemsLayout.Horizontal
};

Esto da lugar a una sola lista de filas, que crece horizontalmente a medida que se agregan nuevos elementos:

Screenshot of a CollectionView horizontal list layout, on iOS and Android

Cuadrícula vertical

En XAML, CollectionView puede mostrar sus elementos en una cuadrícula vertical estableciendo su propiedad ItemsLayout en VerticalGrid:

<CollectionView ItemsSource="{Binding Monkeys}"
                ItemsLayout="VerticalGrid, 2">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="35" />
                    <RowDefinition Height="35" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="80" />
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2"
                       Source="{Binding ImageUrl}"
                       Aspect="AspectFill"
                       HeightRequest="60"
                       WidthRequest="60" />
                <Label Grid.Column="1"
                       Text="{Binding Name}"
                       FontAttributes="Bold"
                       LineBreakMode="TailTruncation" />
                <Label Grid.Row="1"
                       Grid.Column="1"
                       Text="{Binding Location}"
                       LineBreakMode="TailTruncation"
                       FontAttributes="Italic"
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Como alternativa, este diseño también se puede lograr estableciendo la propiedad ItemsLayout en un objeto GridItemsLayout cuya propiedad Orientation está establecida en Vertical:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
       <GridItemsLayout Orientation="Vertical"
                        Span="2" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical)
};

De forma predeterminada, un objeto GridItemsLayout vertical mostrará elementos en una sola columna. Sin embargo, este ejemplo establece la propiedad GridItemsLayout.Span en 2. Esto da lugar a una cuadrícula de dos columnas, que crece verticalmente a medida que se agregan nuevos elementos:

Screenshot of a CollectionView vertical grid layout, on iOS and Android

Cuadrícula horizontal

En XAML, CollectionView puede mostrar sus elementos en una cuadrícula horizontal estableciendo su propiedad ItemsLayout en HorizontalGrid:

<CollectionView ItemsSource="{Binding Monkeys}"
                ItemsLayout="HorizontalGrid, 4">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="35" />
                    <RowDefinition Height="35" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="140" />
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2"
                       Source="{Binding ImageUrl}"
                       Aspect="AspectFill"
                       HeightRequest="60"
                       WidthRequest="60" />
                <Label Grid.Column="1"
                       Text="{Binding Name}"
                       FontAttributes="Bold"
                       LineBreakMode="TailTruncation" />
                <Label Grid.Row="1"
                       Grid.Column="1"
                       Text="{Binding Location}"
                       LineBreakMode="TailTruncation"
                       FontAttributes="Italic"
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Como alternativa, este diseño también se puede lograr estableciendo la propiedad ItemsLayout en un objeto GridItemsLayout cuya propiedad Orientation está establecida en Horizontal:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
       <GridItemsLayout Orientation="Horizontal"
                        Span="4" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemsLayout = new GridItemsLayout(4, ItemsLayoutOrientation.Horizontal)
};

De forma predeterminada, un objeto GridItemsLayout horizontal mostrará elementos en una sola fila. Sin embargo, este ejemplo establece la propiedad GridItemsLayout.Span en 4. Esto da lugar a una cuadrícula de cuatro filas, que crece horizontalmente a medida que se agregan nuevos elementos:

Screenshot of a CollectionView horizontal grid layout, on iOS and Android

Encabezados y pies de página

CollectionView puede presentar un encabezado y pie de página que se desplazan con los elementos de la lista. El encabezado y el pie de página pueden ser cadenas, vistas o objetos DataTemplate.

CollectionView define las siguientes propiedades para especificar el encabezado y el pie de página:

  • Header, de tipo object, especifica la cadena, el enlace o la vista que se mostrarán al principio de la lista.
  • HeaderTemplate, de tipo DataTemplate, especifica el DataTemplate que se va a usar para dar formato a Header.
  • Footer, de tipo object, especifica la cadena, el enlace o la vista que se mostrarán al final de la lista.
  • FooterTemplate, de tipo DataTemplate, especifica el DataTemplate que se va a usar para dar formato a Footer.

Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos.

Cuando se agrega un encabezado a un diseño que crece horizontalmente, de izquierda a derecha, dicho encabezado se muestra a la izquierda de la lista. Del mismo modo, cuando se agrega un pie de página a un diseño que crece horizontalmente, de izquierda a derecha, el pie de página se muestra a la derecha de la lista.

La propiedad Header y Footer se puede establecer en valores string, como se muestra en el siguiente ejemplo:

<CollectionView ItemsSource="{Binding Monkeys}"
                Header="Monkeys"
                Footer="2019">
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    Header = "Monkeys",
    Footer = "2019"
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

Este código da lugar a las capturas de pantalla siguientes, con el encabezado que se muestra en la captura de pantalla de iOS y el pie de página que se muestra en la captura de pantalla de Android:

Screenshot of a CollectionView string header and footer, on iOS and Android

Las propiedades Header y Footer se pueden establecer en una vista. Esto puede ser una sola vista o una vista que contenga varias vistas secundarias. En el siguiente ejemplo, se muestran las propiedades Header y Footer, cada una establecida en un objeto StackLayout que contiene un objeto Label:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.Header>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Monkeys"
                   FontSize="Small"
                   FontAttributes="Bold" />
        </StackLayout>
    </CollectionView.Header>
    <CollectionView.Footer>
        <StackLayout BackgroundColor="LightGray">
            <Label Margin="10,0,0,0"
                   Text="Friends of Xamarin Monkey"
                   FontSize="Small"
                   FontAttributes="Bold" />
        </StackLayout>
    </CollectionView.Footer>
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    Header = new StackLayout
    {
        Children =
        {
            new Label { Text = "Monkeys", ... }
        }
    },
    Footer = new StackLayout
    {
        Children =
        {
            new Label { Text = "Friends of Xamarin Monkey", ... }
        }
    }
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

Este código da lugar a las capturas de pantalla siguientes, con el encabezado que se muestra en la captura de pantalla de iOS y el pie de página que se muestra en la captura de pantalla de Android:

Screenshot of a CollectionView header and footer using views, on iOS and Android

Las propiedades HeaderTemplate y FooterTemplate se pueden establecer en objetos DataTemplate que se usan para dar formato al encabezado y al pie de página. En este escenario, las propiedades Header y Footer deben enlazarse al origen actual de la plantilla que se va a aplicar, como se muestra en el siguiente ejemplo:

<CollectionView ItemsSource="{Binding Monkeys}"
                Header="{Binding .}"
                Footer="{Binding .}">
    <CollectionView.HeaderTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Monkeys"
                       FontSize="Small"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.HeaderTemplate>
    <CollectionView.FooterTemplate>
        <DataTemplate>
            <StackLayout BackgroundColor="LightGray">
                <Label Margin="10,0,0,0"
                       Text="Friends of Xamarin Monkey"
                       FontSize="Small"
                       FontAttributes="Bold" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.FooterTemplate>
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    HeaderTemplate = new DataTemplate(() =>
    {
        return new StackLayout { };
    }),
    FooterTemplate = new DataTemplate(() =>
    {
        return new StackLayout { };
    })
};
collectionView.SetBinding(ItemsView.HeaderProperty, ".");
collectionView.SetBinding(ItemsView.FooterProperty, ".");
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

Este código da lugar a las capturas de pantalla siguientes, con el encabezado que se muestra en la captura de pantalla de iOS y el pie de página que se muestra en la captura de pantalla de Android:

Screenshot of a CollectionView header and footer using templates, on iOS and Android

Espaciado de elementos

De forma predeterminada, no hay ningún espacio entre cada elemento en CollectionView. Este comportamiento se puede cambiar estableciendo propiedades en el diseño de elementos que CollectionView usa.

Cuando CollectionView establece su propiedad ItemsLayout en un objeto LinearItemsLayout, la propiedad LinearItemsLayout.ItemSpacing se puede establecer en un valor double que representa el espacio entre elementos:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Vertical"
                           ItemSpacing="20" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

Nota:

La propiedad LinearItemsLayout.ItemSpacing tiene un conjunto de devolución de llamada de validación, lo que garantiza que el valor de la propiedad sea siempre mayor o igual que 0.

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical)
    {
        ItemSpacing = 20
    }
};

Este código da como resultado una lista vertical de una sola columna, que tiene un espaciado de 20 entre los elementos:

Screenshot of a CollectionView with item spacing, on iOS and Android

Cuando un CollectionView establece su propiedad ItemsLayout en un objeto GridItemsLayout, las propiedades GridItemsLayout.VerticalItemSpacing y GridItemsLayout.HorizontalItemSpacing se pueden establecer en double valores que representan el espacio vacío vertical y horizontalmente entre elementos:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
       <GridItemsLayout Orientation="Vertical"
                        Span="2"
                        VerticalItemSpacing="20"
                        HorizontalItemSpacing="30" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

Nota:

Las propiedades GridItemsLayout.VerticalItemSpacing y GridItemsLayout.HorizontalItemSpacing tienen establecidas devoluciones de llamada de validación, lo que garantiza que los valores de las propiedades sean siempre mayores o iguales que 0.

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemsLayout = new GridItemsLayout(2, ItemsLayoutOrientation.Vertical)
    {
        VerticalItemSpacing = 20,
        HorizontalItemSpacing = 30
    }
};

Este código da como resultado una cuadrícula vertical de dos columnas, con un espaciado vertical de 20 entre elementos y un espaciado horizontal de 30 entre elementos:

Screenshot of a CollectionView with item spacing, on Android

Ajuste de tamaño de elemento

De forma predeterminada, cada elemento de un elemento CollectionView se mide y ajusta individualmente, siempre que los elementos de la interfaz de usuario de DataTemplate no especifiquen tamaños fijos. Este comportamiento, que puede cambiar, se especifica mediante el valor de la propiedad CollectionView.ItemSizingStrategy. Este valor de la propiedad se puede establecer en uno de los valores de la enumeración ItemSizingStrategy:

  • MeasureAllItems: cada elemento se mide individualmente. Este es el valor predeterminado.
  • MeasureFirstItem: solo se mide el primer elemento, con todos los elementos subsiguientes a los que se les da el mismo tamaño que el primer elemento.

Importante

La estrategia de dimensionamiento MeasureFirstItem dará lugar a un mayor rendimiento cuando se usa en situaciones en las que el tamaño del elemento está pensado para ser uniforme en todos los elementos.

En el código de ejemplo siguiente se muestra la propiedad ItemSizingStrategy:

<CollectionView ...
                ItemSizingStrategy="MeasureFirstItem">
    ...
</CollectionView>

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

CollectionView collectionView = new CollectionView
{
    ...
    ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem
};

Cambio de tamaño dinámico de los elementos

Los elementos de un CollectionView objeto se pueden cambiar dinámicamente en tiempo de ejecución, cambiando las propiedades relacionadas con el diseño de los elementos dentro de DataTemplate. Por ejemplo, en el ejemplo de código siguiente se cambian las propiedades HeightRequest y WidthRequest de un objeto Image:

void OnImageTapped(object sender, EventArgs e)
{
    Image image = sender as Image;
    image.HeightRequest = image.WidthRequest = image.HeightRequest.Equals(60) ? 100 : 60;
}

El controlador de eventos OnImageTapped se ejecuta en respuesta a un objeto Image que se está pulsando y cambia las dimensiones de la imagen para que se vea más fácilmente:

Screenshot of a CollectionView with dynamic item sizing, on iOS and Android

Diseño de derecha a izquierda

CollectionView puede diseñar su contenido en una dirección de flujo de derecha a izquierda estableciendo su propiedad RightToLeft en FlowDirection. Sin embargo, la propiedad FlowDirection debe establecerse idealmente en una página o diseño raíz, lo que hace que todos los elementos de la página o diseño raíz respondan a la dirección del flujo:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CollectionViewDemos.Views.VerticalListFlowDirectionPage"
             Title="Vertical list (RTL FlowDirection)"
             FlowDirection="RightToLeft">
    <StackLayout Margin="20">
        <CollectionView ItemsSource="{Binding Monkeys}">
            ...
        </CollectionView>
    </StackLayout>
</ContentPage>

El valor predeterminado FlowDirection de un elemento con un elemento primario es MatchParent. Por lo tanto, CollectionView hereda el valor de la propiedad FlowDirection de StackLayout, que a su vez hereda el valor de la propiedad FlowDirection de ContentPage. El resultado es el diseño de derecha a izquierda que se muestra en las capturas de pantalla siguientes:

Screenshot of a CollectionView right-to-left vertical list layout, on iOS and Android

Para obtener más información sobre la dirección del flujo, consulte Localización de derecha a izquierda.