Mehrfachauswahl im RecyclerView

Kürzlich habe ich eine Leserzuschrift zu meinem Kotlin-Buch erhalten: »Wie realisiert man eine Mehrfachauswahl in einer Liste innerhalb einer Android-App?«. Konkret bezog sich die Frage auf die RecyclerView, die ich im Abschnitt 23.7 »Listen und Tabellen« recht ausführlich behandle.

In meiner Antwort beziehe ich mich auf das im Buch präsentierte Beispielprogramm, das in einer RecyclerView die die deutschen Bundesländer inklusive einiger Eckdaten anzeigt.

Mehrfachauswahl in einer »RecyclerView«

Datenmodell

Die erste Voraussetzung für eine Mehrfachauswahl besteht darin, dass es einen Ort gibt, wo Sie sich die Auswahl merken. In meinem Beispielprogramm ist die Datenquelle einfach ein Array von Country-Objekten. Also habe ich dieser Klasse eine zusätzliche Eigenschaft isSelected hinzugefügt:

class Country(val name: String,
              val area: Double,
              val population: Int,
              val capital: String,
              var isSelected: Boolean = false)  // <- neu!
{
   // Code unverändert ...
}

RecyclerView-Adapter

Im RecyclerView-Adapter ist die Methode onBindViewHolder für die grafische Darstellung der Listenelemente zuständig. Hier müssen Sie Code einbauen, um ausgewählte Einträge optisch hervorzuheben. Ich habe mich dazu entschieden, einfach die Hintergrundfarbe grau statt weiß darzustellen — aber es gibt natürlich viele andere Optionen.

class CountryAdapter(private val countries: List<Country>,
                     private val context: Context)
    : RecyclerView.Adapter<CountryVH>()
{
     ...
    override fun onBindViewHolder(holder: CountryVH,
                                  pos: Int)
    {
        holder.txtCountry.text = countries[pos].name
        // ... usw.

        // neuer Code: Hintergrundfarbe je nach Auswahl
        if (countries[pos].isSelected)
            holder.itemView.setBackgroundColor(Color.LTGRAY)
        else
            holder.itemView.setBackgroundColor(Color.WHITE)
        ...
     }
}

Reaktion auf das On-Click-Ereignis

Ebenfalls in onBindViewHolder wird ein Lambda-Ausdruck übergeben, der immer dann ausgeführt wird, wenn der Benutzer der App einen Eintrag der Liste berührt, um diesen auszuwählen bzw. um die Auswahl wieder aufzuheben. Dort sind zwei Dinge wichtig: Zum Einen wird die isSelected-Eigenschaft des Array-Elements der Datenquelle geändert. Und zum Anderen wird für die gesamte RecyclerView mit notifyDataSetChanged neu gezeichnet. (Andernfalls würde die Statusänderung nicht sofort sichtbar.)

class CountryAdapter(private val countries: List<Country>,
                     private val context: Context)
    : RecyclerView.Adapter<CountryVH>()
{
     ...
    override fun onBindViewHolder(holder: CountryVH,
                                  pos: Int)
    {
        ...
        // Reaktion auf Auswahl des Listeneintrags
        holder.itemView.setOnClickListener {
            // aktuelle Auswahl invertieren
            countries[pos].isSelected = !countries[pos].isSelected
            // ganze Liste neu zeichnen
            this.notifyDataSetChanged()
        }
    }
}

Beispielcode

Den gesamten Beispielcode finden Sie hier zum Download:

https://kofler.info/uploads/kotlin/kap23-recycler-multiselect.zip

Bitte beachten Sie, dass das Beispiel im Vergleich zu den Listings im Buch auf die neue ViewBinding-Technik umgebaut wurde (siehe auch Kotlin-Updates: Android Studio 4.2).