Creare elenchi dinamici con RecyclerView   Parte di Android Jetpack.

Prova Compose
Jetpack Compose è il toolkit UI consigliato per Android. Scopri come lavorare con i layout in Compose.

RecyclerView semplifica la visualizzazione efficiente di grandi set di dati. Fornisci i dati e definisci l'aspetto di ogni elemento. La libreria RecyclerView crea dinamicamente gli elementi quando sono necessari.

Come suggerisce il nome, RecyclerView ricicla i singoli elementi. Quando un elemento scorre fuori dallo schermo, RecyclerView non distrugge la relativa visualizzazione. Al contrario, RecyclerView riutilizza la visualizzazione per i nuovi elementi che sono stati visualizzati sullo schermo. RecyclerView migliora le prestazioni e la reattività dell'app e riduce il consumo di energia.

Classi chiave

Diverse classi collaborano per creare l'elenco dinamico.

  • RecyclerView è il ViewGroup che contiene le visualizzazioni corrispondenti ai dati. È una visualizzazione stessa, quindi aggiungi RecyclerView al layout come faresti con qualsiasi altro elemento UI.

  • Ogni singolo elemento dell'elenco è definito da un oggetto view holder. Quando viene creato il view holder, non ha dati associati. Dopo la creazione del view holder, RecyclerView lo lega ai relativi dati. Definisci il view holder estendendo RecyclerView.ViewHolder.

  • RecyclerView richiede le visualizzazioni e le lega ai relativi dati chiamando i metodi nell'adattatore. Definisci l'adattatore estendendo RecyclerView.Adapter.

  • Il gestore del layout dispone i singoli elementi nell'elenco. Puoi utilizzare uno dei gestori del layout forniti dalla libreria RecyclerView oppure puoi definire il tuo. Tutti i gestori del layout si basano sulla classe astratta LayoutManager della libreria.

Puoi vedere come tutti i componenti si integrano nell'app di esempio RecyclerView (Kotlin) o nell'app di esempio RecyclerView (Java).

Passaggi per implementare RecyclerView

Se intendi utilizzare RecyclerView, devi eseguire alcune operazioni, descritte in dettaglio nelle sezioni seguenti.

  1. Decidi l'aspetto dell'elenco o della griglia. In genere, puoi utilizzare uno dei gestori del layout standard della libreria RecyclerView.

  2. Progetta l'aspetto e il comportamento di ogni elemento dell'elenco. In base a questo progetto, estendi la classe ViewHolder. La tua versione di ViewHolder fornisce tutte le funzionalità per le voci dell'elenco. Il view holder è un wrapper attorno a View, gestita da RecyclerView.

  3. Definisci l'Adapter che associa i dati alle visualizzazioni ViewHolder.

Sono disponibili anche opzioni di personalizzazione avanzate che ti consentono di adattare RecyclerView alle tue esigenze specifiche.

Pianificare il layout

Gli elementi in RecyclerView sono disposti da una LayoutManager classe. La libreria RecyclerView fornisce tre gestori del layout che gestiscono le situazioni di layout più comuni:

  • LinearLayoutManager dispone gli elementi in un elenco unidimensionale.
  • GridLayoutManager dispone gli elementi in una griglia bidimensionale:
    • Se la griglia è disposta verticalmente, GridLayoutManager tenta di fare in modo che tutti gli elementi di ogni riga abbiano la stessa larghezza e altezza, ma righe diverse possono avere altezze diverse.
    • Se la griglia è disposta orizzontalmente, GridLayoutManager tenta di fare in modo che tutti gli elementi di ogni colonna abbiano la stessa larghezza e altezza, ma colonne diverse possono avere larghezze diverse.
  • StaggeredGridLayoutManager è simile a GridLayoutManager, ma non richiede che gli elementi di una riga abbiano la stessa altezza (per le griglie verticali) o che gli elementi della stessa colonna abbiano la stessa larghezza (per le griglie orizzontali). Di conseguenza, gli elementi di una riga o di una colonna possono finire per essere sfalsati l'uno rispetto all'altro.

Devi anche progettare il layout dei singoli elementi. Questo layout è necessario quando progetti il view holder, come descritto nella sezione successiva.

Implementare l'adattatore e il view holder

Una volta determinato il layout, devi implementare Adapter e ViewHolder. Queste due classi collaborano per definire la modalità di visualizzazione dei dati. Il ViewHolder è un wrapper attorno a una View che contiene il layout per un singolo elemento dell'elenco. Adapter crea gli oggetti ViewHolder in base alle esigenze e imposta anche i dati per queste visualizzazioni. Il processo di associazione delle visualizzazioni ai relativi dati è chiamato binding.

Quando definisci l'adattatore, esegui l'override di tre metodi chiave:

  • onCreateViewHolder(): RecyclerView chiama questo metodo ogni volta che deve creare un nuovo ViewHolder. Il metodo crea e inizializza il ViewHolder e la relativa View, ma non compila i contenuti della visualizzazione. Il ViewHolder non è ancora stato associato a dati specifici.

  • onBindViewHolder(): RecyclerView chiama questo metodo per associare un ViewHolder ai dati. Il metodo recupera i dati appropriati e li utilizza per compilare il layout del view holder. Ad esempio, se RecyclerView visualizza un elenco di nomi, il metodo potrebbe trovare il nome appropriato nell'elenco e compilare il widget TextView del view holder.

  • getItemCount(): RecyclerView chiama questo metodo per ottenere le dimensioni del set di dati. Ad esempio, in un'app di rubrica, potrebbe essere il numero totale di indirizzi. RecyclerView lo utilizza per determinare quando non sono presenti altri elementi che possono essere visualizzati.

Ecco un esempio tipico di un adattatore semplice con un ViewHolder nidificato che visualizza un elenco di dati. In questo caso, RecyclerView visualizza un semplice elenco di elementi di testo. All'adattatore viene passato un array di stringhe contenenti il testo per gli elementi ViewHolder.

Kotlin

class CustomAdapter(private val dataSet: Array<String>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder)
     */
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView

        init {
            // Define click listener for the ViewHolder's View
            textView = view.findViewById(R.id.textView)
        }
    }

    // Create new views (invoked by the layout manager)
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        // Create a new view, which defines the UI of the list item
        val view = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.text_row_item, viewGroup, false)

        return ViewHolder(view)
    }

    // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {

        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.textView.text = dataSet[position]
    }

    // Return the size of your dataset (invoked by the layout manager)
    override fun getItemCount() = dataSet.size

}

Java

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {

    private String[] localDataSet;

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder)
     */
    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView textView;

        public ViewHolder(View view) {
            super(view);
            // Define click listener for the ViewHolder's View

            textView = (TextView) view.findViewById(R.id.textView);
        }

        public TextView getTextView() {
            return textView;
        }
    }

    /**
     * Initialize the dataset of the Adapter
     *
     * @param dataSet String[] containing the data to populate views to be used
     * by RecyclerView
     */
    public CustomAdapter(String[] dataSet) {
        localDataSet = dataSet;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view, which defines the UI of the list item
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.text_row_item, viewGroup, false);

        return new ViewHolder(view);
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {

        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.getTextView().setText(localDataSet[position]);
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return localDataSet.length;
    }
}

Come di consueto, il layout per ogni elemento di visualizzazione è definito in un file di layout XML. In questo caso, l'app ha un file text_row_item.xml simile al seguente:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/list_item_height"
    android:layout_marginLeft="@dimen/margin_medium"
    android:layout_marginRight="@dimen/margin_medium"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/element_text"/>
</FrameLayout>

Passaggi successivi

Il seguente snippet di codice mostra come utilizzare RecyclerView.

Kotlin

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val dataset = arrayOf("January", "February", "March")
        val customAdapter = CustomAdapter(dataset)

        val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = customAdapter

    }

}

Java

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.layoutManager = new LinearLayoutManager(this)
recyclerView.setAdapter(customAdapter);

La libreria offre anche molti modi per personalizzare l'implementazione. Per saperne di più, consulta Personalizzazione avanzata di RecyclerView customization.

Attiva la visualizzazione edge-to-edge

Segui questi passaggi per attivare una visualizzazione edge-to-edge per un RecyclerView:

Il seguente video mostra un RecyclerView con la visualizzazione edge-to-edge disattivata (a sinistra) e attivata (a destra):

Esempio di codice inset:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(
  findViewById(R.id.my_recycler_view)
  ) { v, insets ->
      val innerPadding = insets.getInsets(
          WindowInsetsCompat.Type.systemBars()
                  or WindowInsetsCompat.Type.displayCutout()
          // If using EditText, also add
          // "or WindowInsetsCompat.Type.ime()" to
          // maintain focus when opening the IME
      )
      v.setPadding(
          innerPadding.left,
          innerPadding.top,
          innerPadding.right,
          innerPadding.bottom)
      insets
  }
  

Java

ViewCompat.setOnApplyWindowInsetsListener(
  activity.findViewById(R.id.my_recycler_view),
  (v, insets) -> {
      Insets innerPadding = insets.getInsets(
              WindowInsetsCompat.Type.systemBars() |
                      WindowInsetsCompat.Type.displayCutout()
              // If using EditText, also add
              // "| WindowInsetsCompat.Type.ime()" to
              // maintain focus when opening the IME
      );
      v.setPadding(
              innerPadding.left,
              innerPadding.top,
              innerPadding.right,
              innerPadding.bottom
      );
      return insets;
  }
);
  

Il codice XML di RecyclerView:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/my_recycler_view"
    android:clipToPadding="false"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Risorse aggiuntive

Per saperne di più sui test su Android, consulta le seguenti risorse.

Esempi di app