ListView
ListView de .NET Multi-platform App UI (.NET MAUI) muestra una lista vertical desplazable de elementos de datos seleccionables. Aunque ListView administra la apariencia de la lista, la apariencia de cada elemento de la lista se define mediante un DataTemplate que usa Cell para mostrar elementos. .NET MAUI incluye tipos de celda para mostrar combinaciones de texto e imágenes, y también puede definir celdas personalizadas que muestren cualquier contenido que desees. ListView también incluye compatibilidad para mostrar encabezados y pies de página, datos agrupados, elementos de menú contextual y de extracción para actualizar.
El clase ListView se deriva de la clase ItemsView<Cell>
, de la que hereda las propiedades siguientes:
ItemsSource
, de tipoIEnumerable
, especifica la colección de elementos que se mostrarán en el área de sugerencias, y tiene un valor predeterminado denull
.ItemTemplate
, de tipo DataTemplate, especifica la plantilla que se aplicará a cada elemento de la colección de elementos que se mostrará.
ListView define las siguientes propiedades:
Footer
, de tipoobject
, especifica la cadena o vista que se mostrará al final de la lista.FooterTemplate
, de tipo DataTemplate, especifica el DataTemplate que se va a usar para dar formato aFooter
.GroupHeaderTemplate
, de tipo DataTemplate, define el DataTemplate utilizado para definir la apariencia del encabezado de cada grupo. Esta propiedad es mutuamente excluyente con la propiedadGroupDisplayBinding
. Por lo tanto, configurar esta propiedad estableceráGroupDisplayBinding
ennull
.HasUnevenRows
, de tipobool
, indica si los elementos de la lista pueden tener filas de diferentes alturas. El valor predeterminado de esta propiedad esfalse
.Header
, de tipoobject
, especifica la cadena o vista que se mostrará al principio de la lista.HeaderTemplate
, de tipo DataTemplate, especifica el DataTemplate que se va a usar para dar formato aHeader
.HorizontalScrollBarVisibility
, de tipoScrollBarVisibility
, indica cuándo estará visible la barra de desplazamiento horizontal.IsGroupingEnabled
, de tipobool
, indica si los datos subyacentes deben mostrarse en grupos. El valor predeterminado de esta propiedad esfalse
.IsPullToRefreshEnabled
, de tipobool
, indica si el usuario puede deslizar el dedo hacia abajo para hacer que ListView actualice sus datos. El valor predeterminado de esta propiedad esfalse
.IsRefreshing
, de tipobool
, indica si el objeto ListView se está actualizando actualmente. El valor predeterminado de esta propiedad esfalse
.RefreshCommand
, de tipo ICommand, representa el comando que se ejecutará cuando se desencadene una actualización.RefreshControlColor
, de tipo Color, determina el color de la visualización de actualización que se muestra mientras se produce una actualización.RowHeight
, de tipoint
, determina el alto de cada fila cuandoHasUnevenRows
esfalse
.SelectedItem
, de tipoobject
, representa el elemento seleccionado actualmente en ListView.SelectionMode
, de tipoListViewSelectionMode
, indica si los elementos se pueden seleccionar en ListView o no. El valor predeterminado de esta propiedad esSingle
.SeparatorColor
, de tipo Color, define el color de la barra que separa los elementos de la lista.SeparatorVisibility
, de tipoSeparatorVisibility
, define si los separadores son visibles entre los elementos.VerticalScrollBarVisibility
, de tipoScrollBarVisibility
, indica cuándo estará visible la barra de desplazamiento vertical.
Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos y recibir formato de estilo.
Además, ListView define las siguientes propiedades que no están respaldadas por objetos BindableProperty:
GroupDisplayBinding
, de tipoBindingBase
, establece el enlace que se usará para mostrar el encabezado de grupo. Esta propiedad es mutuamente excluyente con la propiedadGroupHeaderTemplate
. Por lo tanto, configurar esta propiedad estableceráGroupHeaderTemplate
ennull
.GroupShortNameBinding
, de tipoBindingBase
, establece el enlace del nombre que se va a mostrar en listas de accesos directos agrupadas.CachingStrategy
, de tipoListViewCachingStrategy
, define la estrategia de reutilización de celdas de ListView. Se trata de una propiedad de solo lectura.
ListView define los siguientes eventos:
ItemAppearing
, que se produce cuando la representación visual de un elemento se agrega al diseño visual de ListView. El objetoItemVisibilityEventArgs
que acompaña al evento define las propiedadesItem
yIndex
.ItemDisappearing
, que se produce cuando la representación visual de un elemento se quita del diseño visual de ListView. El objetoItemVisibilityEventArgs
que acompaña al evento define las propiedadesItem
yIndex
.ItemSelected
, que se genera cuando se selecciona un nuevo elemento de la lista. El objetoSelectedItemChangedEventArgs
que acompaña al evento define las propiedadesSelectedItem
ySelectedItemIndex
.ItemTapped
, que se genera cuando se pulsa un elemento en ListView. El objetoItemTappedEventArgs
que acompaña al evento define las siguientes propiedades:Group
,Item
yItemIndex
.Refreshing
, que se genera cuando se desencadena una operación de extracción para actualizar en ListView.Scrolled
, . El objetoScrolledEventArgs
que acompaña al evento define las propiedadesScrollX
yScrollY
.ScrollToRequested
. El objetoScrollToRequestedEventArgs
que acompaña a este evento define las propiedades Element,Mode
,Position
,ScrollX
,ScrollY
yShouldAnimate
.
Relleno de ListView con datos
ListView se rellena con datos estableciendo su ItemsSource
propiedad en cualquier colección que implemente IEnumerable
.
Importante
Si es necesario que ListView se actualice a medida que se agregan, quitan o cambian elementos en la colección subyacente, la colección subyacente debe ser una IEnumerable
colección que envíe notificaciones de cambio de propiedad, como ObservableCollection
.
ListView se puede rellenar con datos mediante el enlace de datos para enlazar su propiedad ItemsSource
a una colección IEnumerable
. En XAML, esto se consigue mediante la extensión de marcado Binding
.
<ListView ItemsSource="{Binding Monkeys}" />
El código de C# equivalente es el siguiente:
ListView listView = new ListView();
listView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
En este ejemplo, los ItemsSource
datos de propiedad se enlazan a la Monkeys
propiedad del modelo de vista conectado.
Nota:
Los enlaces compilados se pueden habilitar para mejorar el rendimiento del enlace de datos en aplicaciones MAUI de .NET. Para obtener más información, consulta Enlaces compilados.
Para obtener más información sobre el enlace de datos, consulta Enlace de datos.
Definición de la apariencia de elementos
Se puede definir la apariencia de cada elemento de ListView mediante el establecimiento de la propiedad ItemTemplate
en un DataTemplate:
<ListView ItemsSource="{Binding Monkeys}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<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>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Los elementos especificados en el DataTemplate define la apariencia de cada elemento de la lista y el elemento secundario del DataTemplate debe ser un objeto Cell. En este ejemplo, el diseño dentro del DataTemplate se administra mediante un objeto Grid. La Grid contiene un objeto Image y dos objetos Label, que se enlazan a las propiedades de la clase Monkey
:
public class Monkey
{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}
Las capturas de pantalla siguientes muestran el resultado de crear plantillas para cada elemento de la lista:
Para obtener más información sobre las plantillas de datos, consulta Plantillas de datos.
Celdas
La apariencia de cada elemento de un objeto ListView se define mediante DataTemplate y DataTemplate debe hacer referencia a una clase Cell para mostrar elementos. Cada celda representa un elemento de datos en ListView. .NET MAUI incluye las siguientes celdas integradas:
- TextCell, que muestra el texto principal y secundario en líneas independientes.
- ImageCell, que muestra una imagen con texto principal y secundario en líneas independientes.
- SwitchCell, que muestra texto y un conmutador que se pueden activar o desactivar.
- EntryCell, que muestra una etiqueta y un texto que se pueden editar.
- ViewCell, que es una celda personalizada cuya apariencia se define mediante unaView. Este tipo de celda debe usarse cuando se quiera definir completamente la apariencia de cada elemento de una ListView.
Normalmente, SwitchCell y EntryCell solo se usarán en TableView y no en ListView. Para obtener más información sobre SwitchCell y EntryCell, consulta TableView.
Celda de texto
Una TextCell muestra texto principal y secundario en líneas independientes. TextCell define las siguientes propiedades:
Text
, de tipostring
, define el texto principal que se va a mostrar.TextColor
, de tipo Color, representa el color del texto principal.Detail
, de tipostring
, define el texto secundario que se va a mostrar.DetailColor
, de tipo Color, indica el color del texto secundario.Command
, de tipo ICommand, define el comando que se ejecuta cuando se pulsa la celda.CommandParameter
, de tipoobject
, representa el parámetro que se pasa al comando.
Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y que se les puede aplicar un estilo.
En el ejemplo siguiente se muestra cómo usar una TextCell para definir la apariencia de los elementos de una ListView:
<ListView ItemsSource="{Binding Food}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
En la captura de pantalla siguiente se muestra la apariencia resultante de la celda:
Celda de imagen
ImageCell muestra una imagen con texto principal y secundario en líneas independientes. ImageCell hereda las propiedades de TextCell y define la propiedad ImageSource, de tipo ImageSource, que especifica la imagen que se va a mostrar en la celda. Esta propiedad está respaldada por un objeto BindableProperty, lo que significa que puede ser destino de los enlaces de datos, y recibir formato de estilo.
En el ejemplo siguiente se muestra cómo usar la apariencia de un ImageCell para definir el aspecto de los elementos mediante ListView:
<ListView ItemsSource="{Binding Food}">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell ImageSource="{Binding Image}"
Text="{Binding Name}"
Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
En la captura de pantalla siguiente se muestra la apariencia resultante de la celda:
Celda de vista
ViewCell es una celda personalizada cuya apariencia se define mediante View. ViewCell define una propiedad View, de tipo View, que define la vista que representa el contenido de la celda. Esta propiedad está respaldada por un objeto BindableProperty, lo que significa que puede ser destino de los enlaces de datos, y recibir formato de estilo.
Nota:
La propiedad View es la propiedad de contenido de la clase ViewCell y, por tanto, no es necesario establecerla explícitamente desde XAML.
En el ejemplo siguiente se muestra cómo usar una ViewCell para definir la apariencia de los elementos de una ListView:
<ListView ItemsSource="{Binding Monkeys}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<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>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Dentro de ViewCell, el diseño se puede administrar mediante cualquier diseño de .NET MAUI. En este ejemplo, el diseño se administra por un Grid. El Grid contiene un objeto Image y dos objetos Label, que se enlazan a las propiedades de la clase Monkey
.
Las capturas de pantalla siguientes muestran el resultado de crear plantillas para cada elemento de la lista:
Elección de la apariencia del elemento en tiempo de ejecución
La apariencia de cada elemento de ListView se puede elegir a la hora de ejecutarlo, en función del valor del elemento, estableciendo la propiedad ItemTemplate
en un objeto DataTemplateSelector:
<ContentPage ...
xmlns:templates="clr-namespace:ListViewDemos.Templates">
<ContentPage.Resources>
<DataTemplate x:Key="AmericanMonkeyTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="OtherMonkeyTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<templates:MonkeyDataTemplateSelector x:Key="MonkeySelector"
AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
</ContentPage.Resources>
<Grid Margin="20">
<ListView ItemsSource="{Binding Monkeys}"
ItemTemplate="{StaticResource MonkeySelector}" />
</Grid>
</ContentPage>
La propiedad ItemTemplate
se establece en el objeto MonkeyDataTemplateSelector
. En el ejemplo siguiente se muestra la clase MonkeyDataTemplateSelector
:
public class MonkeyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate AmericanMonkey { get; set; }
public DataTemplate OtherMonkey { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
}
}
La clase MonkeyDataTemplateSelector
define propiedades DataTemplate AmericanMonkey
y OtherMonkey
que se establecen en diferentes plantillas de datos. La invalidación de OnSelectTemplate
devuelve la AmericanMonkey
plantilla, que muestra el nombre y la ubicación del mono en verde azulado, cuando el nombre del mono contiene "America". Cuando el nombre del mono no contiene "America", la invalidación de OnSelectTemplate
devuelve la plantilla OtherMonkey
, que muestra el nombre del mono y la ubicación en plata:
Para obtener más información sobre los selectores de plantillas de datos, consulta Creación de un DataTemplateSelector.
Respuesta a la selección de elementos
De manera predeterminada, la selección ListView está habilitada. Pero este comportamiento se puede cambiar modificando la propiedad SelectionMode
. La enumeración ListViewSelectionMode
define los miembros siguientes:
None
: indica que no se puede seleccionar ningún elemento.Single
: indica que se puede seleccionar un solo elemento, con el elemento seleccionado resaltado. Este es el valor predeterminado.
ListView define un evento ItemSelected
que se genera cuando cambia la propiedad SelectedItem
, ya sea debido a que el usuario selecciona un elemento de la lista o cuando una aplicación establece la propiedad. El objeto SelectedItemChangedEventArgs
que acompaña a este evento tiene propiedades SelectedItem
y SelectedItemIndex
.
Cuando la propiedad SelectionMode
se establece en Single
, se puede seleccionar un solo elemento en ListView. Cuando un elemento está seleccionado, la propiedad SelectedItem
se establece en el valor del elemento seleccionado: Cuando la propiedad cambia, se genera el evento ItemSelected
.
En el ejemplo siguiente se muestra un ListView que puede responder a la selección de un solo elemento:
<ListView ItemsSource="{Binding Monkeys}"
ItemSelected="OnItemSelected">
...
</ListView>
En este ejemplo, el controlador de eventos OnItemSelected
se ejecuta cuando se desencadena el evento ItemSelected
, con el controlador de eventos recuperando el elemento seleccionado:
void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
Monkey item = args.SelectedItem as Monkey;
}
En la captura de pantalla siguiente se muestra la selección de un solo elemento en una ListView:
Borrar la selección
La propiedad SelectedItem
se puede borrar estableciéndola, o el objeto al que se enlaza, en null
.
Deshabilitar selección
La selección ListView está habilitada de manera predeterminada. Pero se puede deshabilitar estableciendo la propiedad SelectionMode
en None
:
<ListView ...
SelectionMode="None" />
Cuando la propiedad SelectionMode
se establece en None
, los elementos en ListView no se pueden seleccionar, la propiedad SelectedItem
permanecerá null
y el evento ItemSelected
no se desencadenará.
Datos de caché
ListView es una vista eficaz para mostrar datos, pero tiene algunas limitaciones. El rendimiento del desplazamiento puede sufrir al usar celdas personalizadas, especialmente cuando contienen jerarquías de vistas profundamente anidadas o usan determinados diseños que requieren una medición compleja. Afortunadamente, hay técnicas que se pueden usar para evitar un mal rendimiento de :
Un ListView a menudo se usa para mostrar mucho más datos de los que encajan en la pantalla. Por ejemplo, una aplicación de música podría tener una biblioteca de canciones con miles de entradas. La creación de un elemento para cada entrada desperdiciaría memoria valiosa y funcionaría mal. La creación y destrucción de filas constantemente requeriría que la aplicación crease instancias y limpiase objetos constantemente, lo que también funcionaría mal.
Para conservar la memoria, los equivalentes nativos ListView de cada plataforma tienen características integradas para reutilizar filas. Solo las celdas visibles en pantalla se cargan en memoria y el contenido se carga en celdas existentes. Este patrón impide que la aplicación cree instancias de miles de objetos, lo que ahorra tiempo y memoria.
.NET MAUI permite la reutilización de celdas ListView mediante la enumeración ListViewCachingStrategy
, que define los siguientes miembros:
RetainElement
, especifica que ListView generará una celda para cada elemento de la lista.RecycleElement
, especifica que ListView intentará minimizar su superficie de memoria y velocidad de ejecución mediante el reciclaje de las celdas de la lista.RecycleElementAndDataTemplate
, comoRecycleElement
, al mismo tiempo que también garantiza que cuando ListView usa un objeto DataTemplateSelector, los objetos DataTemplate se almacenen en caché según el tipo de elemento de la lista.
Conservar elementos
La estrategia RetainElement
de almacenamiento en caché especifica que ListView generará una celda para cada elemento de la lista y es el comportamiento ListView predeterminado. Debe usarse en las siguientes circunstancias:
- Cada celda tiene un gran número de enlaces (de 20 a 30+).
- La plantilla de celda cambia con frecuencia.
- Las pruebas revelan que la estrategia
RecycleElement
de almacenamiento en caché da como resultado una velocidad de ejecución reducida.
Es importante reconocer las consecuencias de la estrategia RetainElement
de almacenamiento en caché al trabajar con celdas personalizadas. Cualquier código de inicialización de celda tendrá que ejecutarse para cada creación de celdas, que puede ser varias veces por segundo. En esta circunstancia, las técnicas de diseño que estaban bien en una página, como el uso de varios objetos Grid anidados, se convierten en cuellos de botella de rendimiento cuando se configuran y destruyen en tiempo real a medida que el usuario se desplaza.
Elementos de reciclaje
La estrategia RecycleElement
de almacenamiento en caché especifica que ListView intentará minimizar la superficie de memoria y la velocidad de ejecución mediante el reciclaje de las celdas de la lista. Este modo no siempre ofrece una mejora del rendimiento y se deben realizar pruebas para determinar las mejoras. Pero es la opción preferida y debe usarse en las siguientes circunstancias:
- Cada celda tiene un número de pequeño a moderado de enlaces.
- Cada
BindingContext
de celda define todos los datos de celda. - Cada celda es en gran medida similar, con la plantilla de celda sin cambiar.
Durante la virtualización, la celda tendrá actualizado su contexto de enlace, por lo que si una aplicación usa este modo, debe asegurarse de que las actualizaciones de contexto de enlace se controlan correctamente. Todos los datos sobre la celda deben provenir del contexto de enlace o de los errores de coherencia. Este problema se puede evitar mediante el enlace de datos para mostrar datos de celda. Como alternativa, los datos de celda deben establecerse en la invalidación de OnBindingContextChanged
, en lugar de en el constructor de la celda personalizada, como se muestra en el ejemplo siguiente:
public class CustomCell : ViewCell
{
Image image = null;
public CustomCell()
{
image = new Image();
View = image;
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var item = BindingContext as ImageItem;
if (item != null)
{
image.Source = item.ImageUrl;
}
}
}
Elementos de reciclaje con DataTemplateSelector
Cuando un ListView usa un DataTemplateSelector para seleccionar un DataTemplate, la estrategia RecycleElement
de almacenamiento en caché no almacena en caché objetos DataTemplate. En su lugar, se selecciona un DataTemplate para cada elemento de datos de la lista.
Nota:
La estrategia RecycleElement
de almacenamiento en caché requiere que cuando a DataTemplateSelector se le pide que seleccione un DataTemplate, cada DataTemplate debe devolver el mismo tipo de ViewCell. Por ejemplo, dado un ListView con un DataTemplateSelector que puede devolver MyDataTemplateA
(donde MyDataTemplateA
devuelve un ViewCell de tipo MyViewCellA
), o MyDataTemplateB
(donde MyDataTemplateB
devuelve un ViewCell de tipo MyViewCellB
), cuando MyDataTemplateA
se devuelve, se debe devolver MyViewCellA
o se producirá una excepción.
Elementos de reciclaje con DataTemplates
La estrategia RecycleElementAndDataTemplate
de almacenamiento en caché se basa en la estrategia RecycleElement
de almacenamiento en caché asegurándose además de que cuando un ListView usa un DataTemplateSelector para seleccionar un DataTemplate, los objetos DataTemplate se almacenan en caché por el tipo de elemento de la lista. Por lo tanto, los objetos DataTemplate se seleccionan una vez por tipo de elemento, en lugar de una vez por instancia de elemento.
Nota:
La estrategia RecycleElementAndDataTemplate
de almacenamiento en caché requiere que los objetos DataTemplate devueltos por DataTemplateSelector deben usar el constructor DataTemplate que toma un Type
.
Establecer la estrategia de almacenamiento en caché
La estrategia ListView de almacenamiento en caché se puede definir mediante en XAML estableciendo el atributo CachingStrategy
:
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
En C#, la estrategia de almacenamiento en caché se establece a través de una sobrecarga del constructor:
ListView listView = new ListView(ListViewCachingStrategy.RecycleElement);
Establecer la estrategia de almacenamiento en caché en una listView con subclase
Establecer el atributo CachingStrategy
de XAML en una subclase ListView no generará el comportamiento deseado, ya que no hay ninguna propiedad CachingStrategy
en ListView. La solución a este problema consiste en especificar un constructor en la subclase ListView que acepta un parámetro ListViewCachingStrategy
y lo pasa a la clase base:
public class CustomListView : ListView
{
public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
{
}
...
}
Después, el valor de enumeración ListViewCachingStrategy
se puede especificar desde XAML mediante el atributo x:Arguments
:
<local:CustomListView>
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
</local:CustomListView>
Encabezados y pies de página
ListView 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.
ListView define las siguientes propiedades para especificar el encabezado y el pie de página:
Header
, de tipoobject
, 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 aHeader
.Footer
, de tipoobject
, 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 aFooter
.
Todas estas propiedades están respaldadas por objetos BindableProperty, lo que significa que las propiedades pueden ser destinos de los enlaces de datos.
Muestra cadenas en el encabezado y el pie de página
La propiedad Header
y Footer
se puede establecer en valores string
, como se muestra en el ejemplo siguiente:
<ListView ItemsSource="{Binding Monkeys}"
Header="Monkeys"
Footer="2022">
...
</ListView>
En la captura de pantalla siguiente se muestra el encabezado resultante:
Mostrar vistas en el encabezado y el pie de página
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 ejemplo siguiente se muestran las propiedades Header
y Footer
de cada conjunto en un objeto Grid que contiene un objeto Label:
<ListView ItemsSource="{Binding Monkeys}">
<ListView.Header>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</ListView.Header>
<ListView.Footer>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Monkey"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</ListView.Footer>
...
</ListView>
En la captura de pantalla siguiente se muestra el encabezado resultante:
Mostrar un encabezado y pie de página con plantilla
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 para que se apliquen las plantillas, como se muestra en el ejemplo siguiente:
<ListView ItemsSource="{Binding Monkeys}"
Header="{Binding .}"
Footer="{Binding .}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.FooterTemplate>
<DataTemplate>
<Grid BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Monkey"
FontSize="12"
FontAttributes="Bold" />
</Grid>
</DataTemplate>
</ListView.FooterTemplate>
...
</ListView>
Separadores de elementos de control
De forma predeterminada, los separadores se muestran entre elementos ListView en iOS y Android. Este comportamiento se puede cambiar modificando la propiedad SeparatorVisibility
, de tipo SeparatorVisibility
, en None
:
<ListView ...
SeparatorVisibility="None" />
Además, cuando el separador está habilitado, se puede establecer el color con la propiedad SeparatorColor
:
<ListView ...
SeparatorColor="Blue" />
Tamaño de los elementos
De forma predeterminada, todos los elementos de un elemento ListView tienen el mismo alto, que se deriva del contenido de que DataTemplate define la apariencia de cada elemento. Pero, este comportamiento se puede cambiar con las propiedades HasUnevenRows
y RowHeight
. De manera predeterminada, la propiedad HasUnevenRows
es false
.
La propiedad RowHeight
se puede establecer en un int
que representa el alto de cada elemento de ListView siempre que HasUnevenRows
sea false
. Cuando HasUnevenRows
se establece en true
, cada elemento de ListView puede tener un alto diferente. El alto de cada elemento se derivará del contenido del elemento DataTemplate, por lo que cada elemento se ajustará a su contenido.
Los elementos ListView individuales se pueden cambiar de tamaño mediante programación en tiempo de ejecución cambiando las propiedades relacionadas con el diseño de los elementos dentro de DataTemplate, siempre que la propiedad HasUnevenRows
sea true
. En el ejemplo siguiente se cambia el alto de un objeto Image cuando se pulsa:
void OnImageTapped(object sender, EventArgs args)
{
Image image = sender as Image;
ViewCell viewCell = image.Parent.Parent as ViewCell;
if (image.HeightRequest < 250)
{
image.HeightRequest = image.Height + 100;
viewCell.ForceUpdateSize();
}
}
En este ejemplo, el controlador de eventos OnImageTapped
se ejecuta en respuesta a un objeto Image que se está pulsando. El controlador de eventos actualiza el alto de Image y el método Cell.ForceUpdateSize
actualiza el tamaño de la celda, incluso cuando no está visible actualmente.
Advertencia
El uso excesivo del ajuste de tamaño de elementos dinámicos puede provocar una degradación del rendimiento de ListView.
Diseño de derecha a izquierda
ListView 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://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ListViewDemos.RightToLeftListPage"
Title="Right to left list"
FlowDirection="RightToLeft">
<Grid Margin="20">
<ListView ItemsSource="{Binding Monkeys}">
...
</ListView>
</Grid>
</ContentPage>
El valor predeterminado FlowDirection
de un elemento con un elemento primario es MatchParent
. Por lo tanto, ListView hereda el valor de la propiedad FlowDirection
de Grid, que a su vez hereda el valor de la propiedad FlowDirection
de ContentPage.
Mostrar datos agrupados
Los conjuntos de datos de gran tamaño a menudo se pueden volver inconfundibles cuando se presentan en una lista de desplazamiento continuo. En este escenario, la organización de los datos en grupos puede mejorar la experiencia del usuario al facilitar la navegación por los datos.
Los datos se deben agrupar antes de que se puedan mostrar. Esto se puede lograr mediante la creación de una lista de grupos, donde cada grupo es una lista de elementos. La lista de grupos debe ser una colección de IEnumerable<T>
, donde T
define dos fragmentos de datos:
- Nombre de grupo.
- Una colección
IEnumerable
que define los elementos que pertenecen al grupo.
El proceso de agrupación de datos, por lo tanto, consiste en:
- Crear un tipo que modele un solo elemento.
- Crear un tipo que modele un único grupo de elementos.
- Crear una colección
IEnumerable<T>
, dondeT
es el tipo que modela un único grupo de elementos. Esta colección es una colección de grupos, que almacena los datos agrupados. - Agregar un elemento a la colección
IEnumerable<T>
.
Ejemplo
Al agrupar datos, el primer paso es crear un tipo que modele un solo elemento. En el ejemplo siguiente se muestra la clase Animal
:
public class Animal
{
public string Name { get; set; }
public string Location { get; set; }
public string Details { get; set; }
public string ImageUrl { get; set; }
}
La clase Animal
modela un solo elemento. Después se puede crear un tipo que modele un grupo de elementos En el ejemplo siguiente se muestra la clase AnimalGroup
:
public class AnimalGroup : List<Animal>
{
public string Name { get; private set; }
public AnimalGroup(string name, List<Animal> animals) : base(animals)
{
Name = name;
}
}
La clase AnimalGroup
hereda de la List<T>
y agrega una propiedad Name
que representa el nombre del grupo.
Después se puede crear una colección de grupos IEnumerable<T>
:
public List<AnimalGroup> Animals { get; private set; } = new List<AnimalGroup>();
Este código define una colección denominada Animals
, donde cada elemento de la colección es un objeto AnimalGroup
. Cada objeto AnimalGroup
consta de un nombre y una colección List<Animal>
que define los objetos del grupo Animal
.
Los datos agrupados se pueden agregar a la colección Animals
después:
Animals.Add(new AnimalGroup("Bears", new List<Animal>
{
new Animal
{
Name = "American Black Bear",
Location = "North America",
Details = "Details about the bear go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
},
new Animal
{
Name = "Asian Black Bear",
Location = "Asia",
Details = "Details about the bear go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
},
// ...
}));
Animals.Add(new AnimalGroup("Monkeys", new List<Animal>
{
new Animal
{
Name = "Baboon",
Location = "Africa & Asia",
Details = "Details about the monkey go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
},
new Animal
{
Name = "Capuchin Monkey",
Location = "Central & South America",
Details = "Details about the monkey go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
},
new Animal
{
Name = "Blue Monkey",
Location = "Central and East Africa",
Details = "Details about the monkey go here.",
ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
},
// ...
}));
Este código crea dos grupos en la colección Animals
. El primer AnimalGroup
se denomina Bears
y contiene una colección List<Animal>
de detalles de osos. El segundo AnimalGroup
se denomina Monkeys
y contiene una List<Animal>
colección de detalles de monos.
ListView mostrará los datos agrupados, si los datos se han agrupado correctamente, estableciendo la propiedad IsGroupingEnabled
en true
:
<ListView ItemsSource="{Binding Animals}"
IsGroupingEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<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>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
El código de C# equivalente es el siguiente:
ListView listView = new ListView
{
IsGroupingEnabled = true
};
listView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
// ...
La apariencia de cada elemento en la ListView se define establecido su propiedad ItemTemplate
en un DataTemplate. Para obtener más información, consulta Definir la apariencia del elemento.
En la captura de pantalla siguiente se muestran los ListView datos agrupados:
Nota:
De forma predeterminada, ListView mostrará el nombre del grupo en el encabezado. Este comportamiento se puede cambiar personalizando el encabezado de grupo.
Personalizar el encabezado de grupo
Se puede personalizar la apariencia de cada encabezado de grupo mediante el establecimiento de la propiedad ListView.GroupHeaderTemplate
en DataTemplate:
<ListView ItemsSource="{Binding Animals}"
IsGroupingEnabled="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"
BackgroundColor="LightGray"
FontSize="18"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
...
</ListView>
En este ejemplo, cada encabezado de grupo se establece en una Label que muestra el nombre del grupo y que tiene otras propiedades de apariencia establecidas. En la captura de pantalla siguiente se muestra el encabezado de grupo personalizado:
Importante
La propiedad GroupHeaderTemplate
se excluye mutuamente con la propiedad GroupDisplayBinding
. Por lo tanto, no se deben establecer ambas propiedades.
Agrupar sin plantillas
ListView puede mostrar datos agrupados correctamente sin establecer la propiedad ItemTemplate
en una DataTemplate:
<ListView ItemsSource="{Binding Animals}"
IsGroupingEnabled="true" />
En este escenario, se pueden mostrar datos significativos reemplazando el método ToString
en el tipo que modela un solo elemento y el tipo que modela un único grupo de elementos.
Controlar el desplazamiento
ListView define dos métodos ScrollTo
, que desplazan los elementos a la vista. Una de las sobrecargas desplaza el elemento especificado en la vista, mientras que el otro desplaza el elemento especificado en el grupo especificado a la vista. Las dos sobrecargas tienen argumentos adicionales que permiten especificar la posición exacta del elemento después de que se haya completado el desplazamiento y si se va a animar el desplazamiento.
ListView define un evento ScrollToRequested
que se desencadena cuando se invoca uno de los métodos ScrollTo
. El objeto ScrollToRequestedEventArgs
que acompaña al evento ScrollToRequested
tiene muchas propiedades, como ShouldAnimate
, Element, Mode
y Position
. Algunas de estas propiedades se establecen a partir de los argumentos especificados en las llamadas al método ScrollTo
.
Además, ListView define un evento Scrolled
que se desencadena para indicar que se ha producido el desplazamiento. El objeto ScrolledEventArgs
que acompaña al evento Scrolled
tiene propiedades ScrollX
y ScrollY
.
Detectar desplazamiento
ListView define un evento Scrolled
que se desencadena para indicar que se produjo el desplazamiento. La clase ItemsViewScrolledEventArgs
, que representa al objeto que acompaña al evento Scrolled
, define las siguientes propiedades:
ScrollX
, de tipodouble
, representa la posición X del desplazamiento.ScrollY
, de tipodouble
, representa la posición Y del desplazamiento.
En el ejemplo de XAML siguiente se muestra ListView, que establece un controlador para el evento Scrolled
:
<ListView Scrolled="OnListViewScrolled">
...
</ListView>
El código de C# equivalente es el siguiente:
ListView listView = new ListView();
listView.Scrolled += OnListViewScrolled;
En este ejemplo de código, el controlador de eventos OnListViewScrolled
se ejecuta cuando se desencadena el evento Scrolled
:
void OnListViewScrolled(object sender, ScrolledEventArgs e)
{
// Custom logic
}
Importante
El evento Scrolled
se desencadena para los desplazamientos iniciados por el usuario y para los desplazamientos mediante programación.
Desplazar un elemento a la vista
El método ScrollTo
desplaza el elemento especificado en la vista. Dado un objeto ListView denominado listView
, en el ejemplo siguiente se muestra cómo desplazar el elemento mono násico a la vista:
MonkeysViewModel viewModel = BindingContext as MonkeysViewModel;
Monkey monkey = viewModel.Monkeys.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, ScrollToPosition.MakeVisible, true);
Como alternativa, un elemento de los datos agrupados se puede desplazar a la vista especificando el elemento y el grupo. En el ejemplo siguiente se muestra cómo desplazar el elemento mono násico en el grupo Monos en la vista:
GroupedAnimalsViewModel viewModel = BindingContext as GroupedAnimalsViewModel;
AnimalGroup group = viewModel.Animals.FirstOrDefault(a => a.Name == "Monkeys");
Animal monkey = group.FirstOrDefault(m => m.Name == "Proboscis Monkey");
listView.ScrollTo(monkey, group, ScrollToPosition.MakeVisible, true);
Nota:
El evento ScrollToRequested
se desencadena cuando se invoca el método ScrollTo
.
Deshabilitar la animación de desplazamiento
Se muestra una animación de desplazamiento al desplazar un elemento a la vista. Pero esta animación se puede deshabilitar estableciendo el argumento animated
del método ScrollTo
en false
:
listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: false);
Controlar la posición del desplazamiento
Al desplazarse por un elemento a la vista, se puede especificar la posición exacta del elemento después de que se haya completado el desplazamiento con el argumento position
de los métodos ScrollTo
. Este argumento acepta un miembro de enumeración ScrollToPosition
.
MakeVisible
El miembro ScrollToPosition.MakeVisible
indica que el elemento debe desplazarse hasta que esté visible en la vista:
listView.ScrollTo(monkey, position: ScrollToPosition.MakeVisible, animate: true);
Start
El miembro ScrollToPosition.Start
indica que el elemento debe desplazarse hasta el inicio de la vista:
listView.ScrollTo(monkey, position: ScrollToPosition.Start, animate: true);
Centrar
El miembro ScrollToPosition.Center
indica que el elemento debe desplazarse al centro de la vista:
listView.ScrollTo(monkey, position: ScrollToPosition.Center, animate: true);
Final
El miembro ScrollToPosition.End
indica que el elemento debe desplazarse al final de la vista:
listView.ScrollTo(monkey, position: ScrollToPosition.End, animate: true);
Visibilidad de la barra de desplazamiento
ListView define las propiedades HorizontalScrollBarVisibility
y VerticalScrollBarVisibility
, respaldadas por propiedades enlazables. Estas propiedades obtienen o establecen un valor de enumeración ScrollBarVisibility
que representa cuando la barra de desplazamiento horizontal o vertical está visible. La enumeración ScrollBarVisibility
define los miembros siguientes:
Default
indica el comportamiento predeterminado de la barra de desplazamiento para la plataforma y es el valor predeterminado de las propiedadesHorizontalScrollBarVisibility
yVerticalScrollBarVisibility
.Always
indica que las barras de desplazamiento estarán visibles, incluso cuando el contenido se ajusta en la vista.Never
indica que las barras de desplazamiento no están visibles, incluso si el contenido no encaja en la vista.
Agregar menús contextuales
ListView admite elementos de menús contextuales, que se definen como objetos MenuItem que se agregan a la colección ViewCell.ContextActions
en la DataTemplate de cada elemento:
<ListView x:Name="listView"
ItemsSource="{Binding Monkeys}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Favorite"
Command="{Binding Source={x:Reference listView}, Path=BindingContext.FavoriteCommand}"
CommandParameter="{Binding}" />
<MenuItem Text="Delete"
Command="{Binding Source={x:Reference listView}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
</ViewCell.ContextActions>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Los objetos MenuItem se muestran cuando se hace clic con el botón derecho en un elemento de la ListView :
Para obtener más información sobre los elementos de menú, consulta Mostrar elementos de menú.
Deslizar para actualizar
ListView admite la extracción para actualizar la funcionalidad, lo que permite actualizar los datos que se muestran mediante la extracción en la lista de elementos.
Para habilitar la extracción para actualizar, establezca la propiedad IsPullToRefreshEnabled
en true
. Cuando se desencadena una actualización, ListView genera el evento Refreshing
y la propiedad IsRefreshing
se establecerá en true
. Después, el controlador del evento Refreshing
debe ejecutar el código necesario para actualizar el contenido del ListView o la implementación de ICommand que ejecuta RefreshCommand
tiene que ejecutarlo. Una vez actualizada ListView, la propiedad IsRefreshing
debe establecerse en false
o se debe llamar al método EndRefresh
en la ListView para indicar que la actualización se ha completado.
En el ejemplo siguiente se muestra una ListView que usa la extracción para actualizar:
<ListView ItemsSource="{Binding Animals}"
IsPullToRefreshEnabled="true"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
...
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
En este ejemplo, cuando el usuario inicia una actualización, se ejecuta el ICommand definido por la propiedad RefreshCommand
, que debe actualizar los elementos que se muestran. Se muestra una visualización de actualización mientras se produce, que consta de un círculo de progreso animado. El valor de la propiedad IsRefreshing
indica el estado actual de la operación de restauración de la tabla. Cuando se desencadena una actualización, esta propiedad pasará automáticamente a true
. Una vez completada la actualización, debe restablecer la propiedad a false
.