Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

ListView e Custom Cell

Implementare le ListView con Xamarin.Form, per realizzare app multipiattaforma in grado di girare su Android, iOs e Windows Phone.
Implementare le ListView con Xamarin.Form, per realizzare app multipiattaforma in grado di girare su Android, iOs e Windows Phone.
Link copiato negli appunti

Spesso è necessario presentare all’utente un insieme di elementi che hanno una rappresentazione omogenea, o quasi, per permettergli di selezionare uno di questi e continuare con l’utilizzo dell’app. Xamarin.Forms offre diverse soluzioni:

Elemento Descrizione
ListView È una lista che tende ad avere un ampio numero di elementi dello stesso tipo, la cui presentazione è uniforme e consiste in elementi di tipo Cell di cui si può modificare lo stile
Picker È una (piccola) lista di stringhe di cui è possibile selezionare un solo elemento, ed è impiegata come menu a tendina per la selezione
TableView È un insieme di elementi di tipo Cell usate per mostrare dati o gestire gli input dell’utente.

Una ListView è spesso impiegata in un’app, ed è essenziale modificarla in base alle esigenze. Per fare ciò in Xamarin, è fondamentale ricorrere a implementazioni personalizzate (o custom) delle ViewCell e ListView. In questa lezione vedremo come usare una ListView di base e come definire delle Cell ad-hoc da mostrare nella lista.

Caricamento e binding dei dati

Il metodo più semplice per il caricamento dei dati è di assegnare ad una nuova ListView un elenco di risorse di tipo string, usando la proprietà ItemSource che accetta collezioni che implementano l’interfaccia IEnumerable. Automaticamente viene invocato il metodo ToString sulla collezione, mostrando i dati in una TextCell. Vediamolo con un esempio.

Creiamo una nuova Form Xaml Page e impostiamo come nome ListViewExample. Supponiamo che la nostra app debba visualizzare un lista di ricette di cui abbiamo solo il nome. Per farlo, nel codice XAML basterà aggiungere quanto segue:

<ListView x:Name="recipes"/>

e nel code-behind impostiamo la collezione come segue:

recipes.ItemsSource = new string[]{
  "Pasta Sfoglia",
  "Pizza",
  "Carbonara",
  "Matriciana",
  "Ragù"
};

ottenendo il seguente risultato:

Figura 57. (click per ingrandire)


In questo modo, non è possibile aggiungere un altro elemento alla lista poiché già popolata. Per ovviare al problema, è necessario impiegare una ObservableCollection<T>. All’interno della classe inseriamo:

ObservableCollection<string> rcps = new ObservableCollection<string>();

Mentre nel costruttore sostituiamo il codice precedente con:

recipes.ItemsSource = rcps;
		rcps.Add("Pasta Sfoglia");
		rcps.Add("Pizza");
		rcps.Add("Carbonara");
		rcps.Add("Matriciana");
		rcps.Add("Ragù");
		rcps.Add("Salmone");

La visualizzazione dei contenuti rimarrà inalterata, ma sarà possibile aggiungere altri elementi.

Quanto fatto finora permette di utilizzare le TextCell in automatico, avendo un’implementazione semplice e performante. Analogamente, potremmo usare le ImageCell come elemento della ListView. Ad esempio, definiamo una classe RecipeDataSource (il cui codice è disponibile su GitHub) che fornirà l’insieme di ricette, composte da tre proprietà, e un metodo che restituisce una lista di ricette.

<ListView x:Name="recipes" ItemsSource="{Binding RecipeDataSource}">
			<ListView.ItemTemplate>
			  <DataTemplate>
				<ImageCell   ImageSource="{Binding ImagePath}" Text="{Binding Name}" Detail="{Binding Type}" />
			  </DataTemplate>
			</ListView.ItemTemplate>
		</ListView>

Eseguendo il codice, otteniamo il seguente risultato:

Figura 58. (click per ingrandire)


Come si può notare, in WindowsPhone non si ha un ridimensionamento automatico dell’immagine, come invece accade su Android e iOS. Si tratta di un problema noto, come riportato nella documentazione ufficiale.

Una soluzione che offre la possibilità di creare contenuti ad-hoc per le ListView è creare una definizione personalizzata di Cell per la rappresentazione degli elementi della lista. Ciò è possibile attraverso l’estensione della classe ViewCell, che offre la possibilità di implementare uno specifico Renderer per ogni OS e di istanziare uno specifico controllo nativo, ad esempio le View per Android.

Figura 59. (click per ingrandire)


Il primo passo da compiere è la creazione della nuova Cell. Aggiungiamo al progetto portable una nuova classe con il nome di RecipeCustomCell, che estenderà la classe ViewCell:

public class RecipeCustomCell : ViewCell

Definiamo ora le sue proprietà. Ad esempio, per la proprietà Name:

public static readonly BindableProperty NameProperty =
		BindableProperty.Create("Name", typeof(string), typeof(RecipeCustomCell), "");
		public string Name
		{
			get { return (string)GetValue(NameProperty); }
			set { SetValue(NameProperty, value); }
		}

In questa definizione, sono state utilizzate le classi BindableProperty e BindableObject con i relativi metodi per fornire i meccanismi di propagazione dei cambiamenti tipici del binding.

Come prima, anche la definizione completa di questa classe è reperibile su GitHub.

Successivamente, dobbiamo impostare il DataTemplate della proprietà ItemTemplate della ListView con la nuova Cell. Per farlo è necessario aggiungere al tag della ContentPage il namespace e l’assembly in cui è definita la Cell, attraverso la definizione xmlns:local:

xmlns:local="clr-namespace:HelloXamarin;assembly=HelloXamarin"

e modificare la definizione del DataTemplate:

<DataTemplate>
			<local:RecipeCustomCell Name="{Binding Name}" Type="{Binding Type}" ImagePath="{Binding ImagePath}" />
		</DataTemplate>

Abbiamo così definito per ogni riga della lista una RecipeCustomCell composta da tre proprietà.

L’ultimo aspetto da analizzare riguarda la creazione di un nuovo Renderer per ogni piattaforma, passaggio necessario quando si lavora con le ViewCell. È necessario creare una nuova classe che estenda la classe ViewCellRenderer, che espone metodi come GetCellCore per Android per creare il novo tipo di Cell. Consideriamo, a titolo d’esempio, l’implementazione in Android.

Aggiungiamo al progetto Android la nuova classe RecipeAndroidCustomCellRender, inserendo prima del namespace il codice seguente:

[assembly: ExportRenderer(typeof(RecipeCustomCell), typeof(RecipeAndroidCustomCellRender))]

Viene definito l’attributo ExportRenderer che è usato per registrare il Renderer con Xamarin.Forms. L’attributo si compone di due parametri: nome della Cell e del Renderer.

Resta quindi da sovrascrivere il metodo GetCellCore che, prendendo in ingresso un oggetto di tipo Cell, una View, una ViewGroup e il contesto corrente dell’app, restituisce la cella da mostrare come istanza di View in Android, sfruttando uno specifico layout ad-hoc. In particolare, il metodo può essere riassunto con il seguente schema a blocchi:

Figura 60. (click per ingrandire)


La relativa implementazione è riportata su GitHub.

Infine, per aggiungere il layout per la RecipeCustomCell, è necessario aggiungere alla cartella Resources la cartella Layout e definire un nuovo file XML che conterrà il layout della Cell, qui riportato.

Un processo analogo è compiuto per le altre due piattaforme:

iOS sovrascrivere il metodo GetCell, come riportato qui, e aggiungere l’apposito layout, reperibile qui
WindowsPhone sovrascrivere il metodo GetTemplate, come riportato qui, e modificare il DataTemplate della classe App.xaml (codice)

Effettuate queste modifiche, è possibile eseguire l’app su tutte e tre le piattaforme ottenendo il seguente risultato:

Figura 61. (click per ingrandire)



Ti consigliamo anche