Personalización de la apariencia de las celdas de ListView
La clase Xamarin.FormsListView
se usa para presentar listas desplazables, que se pueden personalizar mediante el uso de elementos ViewCell
. Un elemento ViewCell
puede mostrar texto e imágenes, indicar un estado true/false y recibir la entrada del usuario.
Celdas integradas
Xamarin.Forms incluye celdas integradas que funcionan para muchas aplicaciones:
- Los controles
TextCell
se usan para mostrar texto con una segunda línea opcional para el texto detallado. - Los controles
ImageCell
son similares aTextCell
, pero incluyen una imagen a la izquierda del texto. - Los controles
SwitchCell
se usan para presentar y capturar los estados activado/desactivado o true/false. - Los controles
EntryCell
se usan para presentar datos de texto que el usuario puede editar.
Los controles SwitchCell
y EntryCell
se usan con más frecuencia en el contexto de una instancia de TableView
.
TextCell
TextCell
es una celda para mostrar texto, opcionalmente con una segunda línea como texto de detalle. En la captura de pantalla siguiente se muestran elementos TextCell
en iOS y Android:
TextCells se representan como controles nativos en tiempo de ejecución, por lo que el rendimiento es muy bueno en comparación con una instancia personalizada de ViewCell
. TextCells son personalizables, lo que le permite establecer las siguientes propiedades:
Text
: el texto que se muestra en la primera línea, en una fuente grande.Detail
: el texto que se muestra debajo de la primera línea, en una fuente más pequeña.TextColor
: el color del texto.DetailColor
: el color del texto de detalle
En la captura de pantalla siguiente se muestran elementos TextCell
con propiedades de color personalizadas:
ImageCell
ImageCell
, como TextCell
, se puede usar para mostrar texto y texto de detalle secundario, y ofrece un gran rendimiento mediante el uso de los controles nativos de cada plataforma. ImageCell
difiere de TextCell
en que muestra una imagen a la izquierda del texto.
En la captura de pantalla siguiente se muestran elementos ImageCell
en iOS y Android:
ImageCell
resulta útil cuando es necesario mostrar una lista de datos con un aspecto visual, como una lista de contactos o películas. Los elemento ImageCell
son personalizables, lo que le permite establecer lo siguiente:
Text
: el texto que se muestra en la primera línea, en una fuente grandeDetail
: el texto que se muestra debajo de la primera línea, en una fuente más pequeñaTextColor
: el color del textoDetailColor
: el color del texto de detalleImageSource
: la imagen que se va a mostrar junto al texto
En la captura de pantalla siguiente se muestran elementos ImageCell
con propiedades de color personalizadas:
Celdas personalizadas
Las celdas personalizadas permiten crear diseños de celda que no son compatibles con las celdas integradas. Por ejemplo, es posible que quiera presentar una celda con dos etiquetas que tengan un peso equivalente. Un elemento TextCell
sería insuficiente porque TextCell
tiene una etiqueta que es más pequeña. La mayoría de las personalizaciones de celdas agregan datos adicionales de solo lectura (como etiquetas adicionales, imágenes u otra información de visualización).
Todas las celdas personalizadas deben derivar de ViewCell
, la misma clase base que usan todos los tipos de celda integrados.
Xamarin.Forms ofrece un comportamiento de almacenamiento en caché en el control ListView
que puede mejorar el rendimiento de desplazamiento para algunos tipos de celdas personalizadas.
En la captura de pantalla siguiente se muestra un ejemplo de una celda personalizada:
XAML
La celda personalizada que se muestra en la captura de pantalla anterior se puede crear con el código XAML siguiente:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="demoListView.ImageCellPage">
<ContentPage.Content>
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding image}" />
<Label Text="{Binding title}"
TextColor="#f35e20" />
<Label Text="{Binding subtitle}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
El código XAML funciona de la siguiente manera:
- La celda personalizada se anida dentro de
DataTemplate
, que está dentro deListView.ItemTemplate
. Es el mismo proceso que usar cualquier celda integrada. ViewCell
es el tipo de la celda personalizada. El elemento secundario del elementoDataTemplate
debe ser de la claseViewCell
, o bien derivarse de ella.- Dentro de
ViewCell
, cualquier diseño de Xamarin.Forms puede administrar el diseño. En este ejemplo, el diseño se administra medianteStackLayout
, que permite personalizar el color de fondo.
Nota:
Cualquier propiedad de StackLayout
que se pueda enlazar se puede enlazar dentro de una celda personalizada. Pero esta funcionalidad no se muestra en el ejemplo de XAML.
Código
Una celda personalizada también se puede crear en el código. En primer lugar, se debe crear una clase personalizada que derive de ViewCell
:
public class CustomCell : ViewCell
{
public CustomCell()
{
//instantiate each of our views
var image = new Image ();
StackLayout cellWrapper = new StackLayout ();
StackLayout horizontalLayout = new StackLayout ();
Label left = new Label ();
Label right = new Label ();
//set bindings
left.SetBinding (Label.TextProperty, "title");
right.SetBinding (Label.TextProperty, "subtitle");
image.SetBinding (Image.SourceProperty, "image");
//Set properties for desired design
cellWrapper.BackgroundColor = Color.FromHex ("#eee");
horizontalLayout.Orientation = StackOrientation.Horizontal;
right.HorizontalOptions = LayoutOptions.EndAndExpand;
left.TextColor = Color.FromHex ("#f35e20");
right.TextColor = Color.FromHex ("503026");
//add views to the view hierarchy
horizontalLayout.Children.Add (image);
horizontalLayout.Children.Add (left);
horizontalLayout.Children.Add (right);
cellWrapper.Children.Add (horizontalLayout);
View = cellWrapper;
}
}
En el constructor de la página, la propiedad ItemTemplate
de ListView se establece en un objeto DataTemplate
con el tipo CustomCell
especificado:
public partial class ImageCellPage : ContentPage
{
public ImageCellPage ()
{
InitializeComponent ();
listView.ItemTemplate = new DataTemplate (typeof(CustomCell));
}
}
Cambios de contexto de enlace
Al enlazar a las instancias de BindableProperty
de un tipo de celda personalizado, los controles de interfaz de usuario que muestran los valores BindableProperty
deben usar la invalidación OnBindingContextChanged
para establecer los datos que se mostrarán en cada celda, en lugar del constructor de celdas, como se muestra en el ejemplo de código siguiente:
public class CustomCell : ViewCell
{
Label nameLabel, ageLabel, locationLabel;
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(CustomCell), "Name");
public static readonly BindableProperty AgeProperty =
BindableProperty.Create ("Age", typeof(int), typeof(CustomCell), 0);
public static readonly BindableProperty LocationProperty =
BindableProperty.Create ("Location", typeof(string), typeof(CustomCell), "Location");
public string Name
{
get { return(string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}
public int Age
{
get { return(int)GetValue (AgeProperty); }
set { SetValue (AgeProperty, value); }
}
public string Location
{
get { return(string)GetValue (LocationProperty); }
set { SetValue (LocationProperty, value); }
}
...
protected override void OnBindingContextChanged ()
{
base.OnBindingContextChanged ();
if (BindingContext != null)
{
nameLabel.Text = Name;
ageLabel.Text = Age.ToString ();
locationLabel.Text = Location;
}
}
}
Se llamará a la invalidación de OnBindingContextChanged
cuando se desencadene el evento BindingContextChanged
, en respuesta al cambio del valor de la propiedad BindingContext
. Por tanto, cuando cambia BindingContext
, los controles de interfaz de usuario que muestran los valores BindableProperty
deben establecer sus datos. Tenga en cuenta que se debe comprobar si BindingContext
tiene un valor null
, ya que esto se puede establecer mediante Xamarin.Forms para la recolección de elementos no utilizados, lo que a su vez hará que se llame a la invalidación de OnBindingContextChanged
.
Como alternativa, los controles de interfaz de usuario se pueden enlazar a las instancias de BindableProperty
para mostrar sus valores, lo que elimina la necesidad de invalidar el método OnBindingContextChanged
.
Nota:
Al invalidar OnBindingContextChanged
, asegúrese de llamar al método OnBindingContextChanged
de la clase base para que los delegados registrados reciban el evento BindingContextChanged
.
En XAML, el enlace del tipo de celda personalizado a los datos se puede lograr como se muestra en el ejemplo de código siguiente:
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomCell Name="{Binding Name}" Age="{Binding Age}" Location="{Binding Location}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Esto enlaza las propiedades enlazables Name
, Age
y Location
de la instancia de CustomCell
, a las propiedades Name
, Age
y Location
de cada objeto de la colección subyacente.
En el siguiente ejemplo de código, se muestra el enlace equivalente en C#:
var customCell = new DataTemplate (typeof(CustomCell));
customCell.SetBinding (CustomCell.NameProperty, "Name");
customCell.SetBinding (CustomCell.AgeProperty, "Age");
customCell.SetBinding (CustomCell.LocationProperty, "Location");
var listView = new ListView
{
ItemsSource = people,
ItemTemplate = customCell
};
En iOS y Android, si ListView
recicla elementos y la celda personalizada usa un representador personalizado, el representador personalizado debe implementar correctamente la notificación de cambio de propiedad. Cuando se reutilizan las celdas, sus valores de propiedad cambiarán cuando el contexto de enlace se actualice a la de una celda disponible, con los eventos PropertyChanged
generados. Para más información, vea Personalización de una instancia de ViewCell. Para más información sobre el reciclaje de celdas, vea Estrategia de almacenamiento en caché.