Condividi tramite


Personalizzazione dell'aspetto di un controllo ListView con Xamarin.Android

L'aspetto di un controllo ListView è determinato dal layout delle righe visualizzate. Per modificare l'aspetto di un oggetto ListView, usare un layout di riga diverso.

Visualizzazioni di riga predefinite

Sono disponibili dodici visualizzazioni predefinite a cui è possibile fare riferimento usando Android.Resource.Layout:

  • TestListItem : riga di testo singola con formattazione minima.

  • SimpleListItem1 : riga di testo singola.

  • SimpleListItem2 : due righe di testo.

  • SimpleSelectableListItem : riga di testo singola che supporta la selezione di un singolo o più elementi (aggiunta nel livello API 11).

  • SimpleListItemActivated1 : simile a SimpleListItem1, ma il colore di sfondo indica quando viene selezionata una riga (aggiunta nel livello API 11).

  • SimpleListItemActivated2 : simile a SimpleListItem2, ma il colore di sfondo indica quando viene selezionata una riga (aggiunta nel livello API 11).

  • SimpleListItemChecked : visualizza i segni di spunta per indicare la selezione.

  • SimpleListItemMultipleChoice : visualizza le caselle di controllo per indicare la selezione a scelta multipla.

  • SimpleListItemSingleChoice : visualizza i pulsanti di opzione per indicare la selezione reciproca esclusiva.

  • TwoLineListItem : due righe di testo.

  • ActivityListItem : riga di testo singola con un'immagine.

  • SimpleExpandableListItem : raggruppa le righe per categorie e ogni gruppo può essere espanso o compresso.

A ogni visualizzazione riga predefinita è associato uno stile incorporato. Questi screenshot mostrano come viene visualizzata ogni visualizzazione:

Screenshot di TestListItem, SimpleSelectableListItem, SimpleListitem1 e SimpleListItem2

Screenshot di SimpleListItemActivated1, SimpleListItemActivated2, SimpleListItemChecked e SimpleListItemMultipleChecked

Screenshot di SimpleListItemSingleChoice, TwoLineListItem, ActivityListItem e SimpleExpandableListItem

Il file di esempio BuiltInViews/HomeScreenAdapter.cs (nella soluzione BuiltInViews ) contiene il codice per produrre le schermate delle voci di elenco non espandibili. La vista viene impostata nel GetView metodo come segue:

view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);

Le proprietà della visualizzazione possono quindi essere impostate facendo riferimento agli identificatori Text1Text2 di controllo standard e Icon in Android.Resource.Id (non impostare le proprietà che la vista non contiene o verrà generata un'eccezione):

view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Android.Resource.Id.Text2).Text = item.SubHeading;
view.FindViewById<ImageView>(Android.Resource.Id.Icon).SetImageResource(item.ImageResourceId); // only use with ActivityListItem

Il file di esempio BuiltInExpandableViews/ExpandableScreenAdapter.cs (nella soluzione BuiltInViews ) contiene il codice per produrre la schermata SimpleExpandableListItem. La visualizzazione gruppo viene impostata nel GetGroupView metodo come segue:

view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleExpandableListItem1, null);

La visualizzazione figlio viene impostata nel GetChildView metodo come segue:

view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleExpandableListItem2, null);

Le proprietà per la visualizzazione gruppo e la visualizzazione figlio possono quindi essere impostate facendo riferimento agli identificatori standard Text1 e Text2 di controllo, come illustrato in precedenza. Lo screenshot SimpleExpandableListItem (illustrato sopra) fornisce un esempio di visualizzazione di un gruppo a una riga (SimpleExpandableListItem1) e di una visualizzazione figlio a due righe (SimpleExpandableListItem2). In alternativa, la visualizzazione gruppo può essere configurata per due righe (SimpleExpandableListItem2) e la visualizzazione figlio può essere configurata per una riga (SimpleExpandableListItem1) oppure entrambe le visualizzazioni di gruppo e figlio possono avere lo stesso numero di righe.

Accessori

Le righe possono avere accessori aggiunti a destra della visualizzazione per indicare lo stato di selezione:

  • SimpleListItemChecked : crea un elenco a selezione singola con un segno di spunta come indicatore.

  • SimpleListItemSingleChoice : crea elenchi di tipo pulsante di opzione in cui è possibile scegliere una sola opzione.

  • SimpleListItemMultipleChoice : crea elenchi di tipi di casella di controllo in cui sono possibili più scelte.

Gli accessori menzionati sopra sono illustrati nelle schermate seguenti, nel rispettivo ordine:

Screenshot di SimpleListItemChecked, SimpleListItemSingleChoice e SimpleListItemMultipleChoice con accessori

Per visualizzare uno di questi accessori, passare l'ID risorsa di layout richiesto all'adattatore e quindi impostare manualmente lo stato di selezione per le righe necessarie. Questa riga di codice mostra come creare e assegnare un oggetto Adapter usando uno di questi layout:

ListAdapter = new ArrayAdapter<String>(this, Android.Resource.Layout.SimpleListItemChecked, items);

L'oggetto ListView stesso supporta diverse modalità di selezione, indipendentemente dall'accessorio visualizzato. Per evitare confusione, utilizzare la Single modalità di selezione con SingleChoice accessori e la Checked modalità o Multiple con lo MultipleChoice stile. La modalità di selezione è controllata dalla ChoiceMode proprietà dell'oggetto ListView.

Gestione del livello API

Le versioni precedenti di Xamarin.Android hanno implementato enumerazioni come proprietà integer. La versione più recente ha introdotto i tipi di enumerazione .NET appropriati che semplificano notevolmente l'individuazione delle possibili opzioni.

A seconda del livello API di destinazione, ChoiceMode è un numero intero o un'enumerazione. Il file di esempio AccessoryViews/HomeScreen.cs ha un blocco impostato come commento se si vuole impostare come destinazione l'API Gingerbread:

// For targeting Gingerbread the ChoiceMode is an int, otherwise it is an
// enumeration.

lv.ChoiceMode = Android.Widget.ChoiceMode.Single; // 1
//lv.ChoiceMode = Android.Widget.ChoiceMode.Multiple; // 2
//lv.ChoiceMode = Android.Widget.ChoiceMode.None; // 0

// Use this block if targeting Gingerbread or lower
/*
lv.ChoiceMode = 1; // Single
//lv.ChoiceMode = 0; // none
//lv.ChoiceMode = 2; // Multiple
//lv.ChoiceMode = 3; // MultipleModal
*/

Selezione di elementi a livello di codice

L'impostazione manuale degli elementi selezionati viene eseguita con il SetItemChecked metodo (può essere chiamato più volte per più selezioni):

// Set the initially checked row ("Fruits")
lv.SetItemChecked(1, true);

Il codice deve anche rilevare selezioni singole in modo diverso da più selezioni. Per determinare quale riga è stata selezionata in Single modalità utilizzare la CheckedItemPosition proprietà Integer:

FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPosition

Per determinare quali righe sono state selezionate in Multiple modalità è necessario scorrere in ciclo .CheckedItemPositions SparseBooleanArray Una matrice di tipo sparse è simile a un dizionario che contiene solo voci in cui è stato modificato il valore, quindi è necessario attraversare l'intera matrice cercando i valori per true sapere cosa è stato selezionato nell'elenco, come illustrato nel frammento di codice seguente:

var sparseArray = FindViewById<ListView>(Android.Resource.Id.List).CheckedItemPositions;
for (var i = 0; i < sparseArray.Size(); i++ )
{
   Console.Write(sparseArray.KeyAt(i) + "=" + sparseArray.ValueAt(i) + ",");
}
Console.WriteLine();

Creazione di layout di riga personalizzati

Le quattro visualizzazioni di riga predefinite sono molto semplici. Per visualizzare layout più complessi (ad esempio un elenco di messaggi di posta elettronica o tweet o informazioni di contatto) è necessaria una visualizzazione personalizzata. Le visualizzazioni personalizzate vengono in genere dichiarate come file AXML nella directory Resources/Layout e quindi caricate usando il relativo ID risorsa da un adattatore personalizzato. La visualizzazione può contenere un numero qualsiasi di classi di visualizzazione(ad esempio TextViews, ImageViews e altri controlli) con colori personalizzati, tipi di carattere e layout.

Questo esempio è diverso dagli esempi precedenti in diversi modi:

  • Eredita da , non ListActivity da Activity . È possibile personalizzare le righe per qualsiasi ListView controllo , ma è anche possibile includere altri controlli in un Activity layout, ad esempio un'intestazione, pulsanti o altri elementi dell'interfaccia utente. In questo esempio viene aggiunta un'intestazione sopra l'oggetto ListView da illustrare.

  • Richiede un file di layout AXML per la schermata; negli esempi precedenti non ListActivity richiede un file di layout. Questo oggetto AXML contiene una dichiarazione di ListView controllo.

  • Richiede un file di layout AXML per eseguire il rendering di ogni riga. Questo file AXML contiene i controlli di testo e immagine con impostazioni personalizzate di carattere e colore.

  • Usa un file XML del selettore personalizzato facoltativo per impostare l'aspetto della riga quando viene selezionato.

  • L'implementazione Adapter restituisce un layout personalizzato dall'override GetView .

  • ItemClick deve essere dichiarato in modo diverso (un gestore eventi è associato a ListView.ItemClick anziché a un override OnListItemClick in ListActivity).

Queste modifiche sono dettagliate di seguito, a partire dalla creazione della visualizzazione dell'attività e dalla visualizzazione riga personalizzata e quindi dalle modifiche apportate all'adapter e all'attività per eseguirne il rendering.

Aggiunta di un controllo ListView a un layout di attività

Poiché HomeScreen non eredita più da ListActivity essa non ha una visualizzazione predefinita, pertanto è necessario creare un file AXML di layout per la visualizzazione homescreen. Per questo esempio, la vista avrà un'intestazione (usando un TextView) e un ListView oggetto per visualizzare i dati. Il layout è definito nel file Resources/Layout/HomeScreen.axml , illustrato di seguito:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent">
    <TextView android:id="@+id/Heading"
        android:text="Vegetable Groups"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#00000000"
        android:textSize="30dp"
        android:textColor="#FF267F00"
        android:textStyle="bold"
        android:padding="5dp"
    />
    <ListView android:id="@+id/List"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#FFDAFF7F"
    />
</LinearLayout>

Il vantaggio dell'uso di un oggetto Activity con un layout personalizzato (invece di un ListActivity) consiste nell'aggiungere altri controlli alla schermata, ad esempio l'intestazione TextView in questo esempio.

Creazione di un layout di riga personalizzato

È necessario un altro file di layout AXML per contenere il layout personalizzato per ogni riga che verrà visualizzata nella visualizzazione elenco. In questo esempio la riga avrà uno sfondo verde, un testo marrone e un'immagine allineata a destra. Il markup XML Android per dichiarare questo layout è descritto in Resources/Layout/CustomView.axml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:background="#FFDAFF7F"
   android:padding="8dp">
    <LinearLayout android:id="@+id/Text"
       android:orientation="vertical"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:paddingLeft="10dip">
        <TextView
         android:id="@+id/Text1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textColor="#FF7F3300"
         android:textSize="20dip"
         android:textStyle="italic"
         />
        <TextView
         android:id="@+id/Text2"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textSize="14dip"
         android:textColor="#FF267F00"
         android:paddingLeft="100dip"
         />
    </LinearLayout>
    <ImageView
        android:id="@+id/Image"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:padding="5dp"
        android:src="@drawable/icon"
        android:layout_alignParentRight="true" />
</RelativeLayout >

Anche se un layout di riga personalizzato può contenere molti controlli diversi, le prestazioni di scorrimento possono essere influenzate da progettazioni complesse e dall'uso di immagini (soprattutto se devono essere caricate in rete). Per altre informazioni sulla risoluzione dei problemi di prestazioni di scorrimento, vedi l'articolo di Google.

Riferimento a una visualizzazione riga personalizzata

L'implementazione dell'esempio di adattatore personalizzato è in HomeScreenAdapter.cs. Il metodo key è GetView il percorso in cui carica l'AXML personalizzato usando l'ID Resource.Layout.CustomViewrisorsa e quindi imposta le proprietà su ognuno dei controlli nella visualizzazione prima di restituirlo. Viene visualizzata la classe dell'adattatore completa:

public class HomeScreenAdapter : BaseAdapter<TableItem> {
   List<TableItem> items;
   Activity context;
   public HomeScreenAdapter(Activity context, List<TableItem> items)
       : base()
   {
       this.context = context;
       this.items = items;
   }
   public override long GetItemId(int position)
   {
       return position;
   }
   public override TableItem this[int position]
   {
       get { return items[position]; }
   }
   public override int Count
   {
       get { return items.Count; }
   }
   public override View GetView(int position, View convertView, ViewGroup parent)
   {
       var item = items[position];
       View view = convertView;
       if (view == null) // no view to re-use, create new
           view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
       view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
       view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;
       view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId);
       return view;
   }
}

Riferimento a ListView personalizzato nell'attività

Poiché la HomeScreen classe eredita ora da Activity, un ListView campo viene dichiarato nella classe in modo che contenga un riferimento al controllo dichiarato in AXML:

ListView listView;

La classe deve quindi caricare il layout personalizzato dell'attività AXML usando il SetContentView metodo . Può quindi trovare il ListView controllo nel layout, quindi crea e assegna l'adattatore e assegna il gestore di clic. Il codice per il metodo OnCreate è illustrato di seguito:

SetContentView(Resource.Layout.HomeScreen); // loads the HomeScreen.axml as this activity's view
listView = FindViewById<ListView>(Resource.Id.List); // get reference to the ListView in the layout

// populate the listview with data
listView.Adapter = new HomeScreenAdapter(this, tableItems);
listView.ItemClick += OnListItemClick;  // to be defined

Infine, è necessario definire il ItemClick gestore. In questo caso viene visualizzato solo un Toast messaggio:

void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
   var listView = sender as ListView;
   var t = tableItems[e.Position];
   Android.Widget.Toast.MakeText(this, t.Heading, Android.Widget.ToastLength.Short).Show();
}

La schermata risultante è simile alla seguente:

Screenshot dell'oggetto CustomRowView risultante

Personalizzazione del colore del selettore di riga

Quando viene toccato, una riga deve essere evidenziata per il feedback degli utenti. Quando una visualizzazione personalizzata specifica come colore di sfondo come CustomView.axml , esegue anche l'override dell'evidenziazione della selezione. Questa riga di codice in CustomView.axml imposta lo sfondo su verde chiaro, ma significa anche che non è presente alcun indicatore visivo quando viene toccata la riga:

android:background="#FFDAFF7F"

Per riabilitare il comportamento di evidenziazione e anche per personalizzare il colore usato, impostare l'attributo di sfondo su un selettore personalizzato. Il selettore dichiara sia il colore di sfondo predefinito che il colore di evidenziazione. Il file Resources/Drawable/CustomSelector.xml contiene la dichiarazione seguente:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
  android:state_selected="false"
  android:drawable="@color/cellback" />
<item android:state_pressed="true" >
  <shape>
     <gradient
      android:startColor="#E77A26"
        android:endColor="#E77A26"
        android:angle="270" />
  </shape>
</item>
<item android:state_selected="true"
  android:state_pressed="false"
  android:drawable="@color/cellback" />
</selector>

Per fare riferimento al selettore personalizzato, modificare l'attributo di sfondo in CustomView.axml in:

android:background="@drawable/CustomSelector"

Una riga selezionata e il messaggio corrispondente Toast è ora simile al seguente:

Riga selezionata in arancione, con messaggio avviso popup che visualizza il nome della riga selezionata

Prevenzione dello sfarfallio nei layout personalizzati

Android tenta di migliorare le prestazioni dello ListView scorrimento memorizzando nella cache le informazioni sul layout. Se sono presenti elenchi di dati a scorrimento lunghi, è necessario impostare anche la android:cacheColorHint proprietà sulla ListView dichiarazione nella definizione AXML dell'attività (allo stesso valore di colore dello sfondo del layout di riga personalizzato). Se non si include questo hint, potrebbe verificarsi uno sfarfallio quando l'utente scorre un elenco con colori di sfondo di riga personalizzati.