AndroidKotlin

RecyclerView – Utilisation du FlexibleAdapter avec un seul item

By 11 février 2019 No Comments

Nous allons voir dans cette article comment utiliser un flexible adapter provenant de la librairie suivante :

https://github.com/davideas/FlexibleAdapter

Le projet est disponible ici

Cette article montre la mise en place de ce Flexible Adapter n’utilisant qu’un seul type d’item. L’utilisation du flexible adapter n’a donc pas grand intérêt dans ce cas là. Un second, disponible ici, article vous montrera l’utilisation de plusieurs items au sein d’un seul et même adapter.

Voici une capture d’écran du résultat final

.

.

1 – Voici l’activité principale de l’application

class MainActivity : AppCompatActivity(), OrderFlexibleAdapter.OrderListener {

    private var orderList = ArrayList<Order>()

    private lateinit var orderListAdapter: OrderFlexibleAdapter

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

        orderListAdapter = OrderFlexibleAdapter(orderList, this)

        laListe.apply {
            layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
            adapter = orderListAdapter
        }

        val order1 = Order(1, "Titre 1", "Sous titre 1", false)
        val order2 = Order(2, "Titre 2", "Sous titre 2", false)
        // [...]
        val order20 = Order(20, "Titre 20", "Sous titre 20", false)

        orderList.add(order1)
        orderList.add(order2)
        // [...]
        orderList.add(order20)

        orderList.let {
            orderListAdapter.setData(it)
        }

        btnValidate.setOnClickListener {
            afficherLeResultat(orderList)
        }
    }

    private fun afficherLeResultat(orderList: ArrayList<Order>) {

        textResult.text = "Vous avez cliqué sur : "
        orderList.filter { it.validate == true }.apply {

            this.forEach {
                textResult.text = textResult.text.toString() + "${it.id} - "
            }
        }
    }

    override fun onOrderClicked(orderId: Int) {
        orderList.find { it.id == orderId }?.apply {
            this.validate = !this.validate
        }

        orderListAdapter.updateData()
    }
}

.

Voici le layout associé à cette activité

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Exemple d'utilisation d'un Flexible Adapter "
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" android:id="@+id/textView"/>

    <android.support.v7.widget.RecyclerView
            android:id="@+id/laListe"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintTop_toBottomOf="@+id/textView"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="8dp" 
            app:layout_constraintBottom_toTopOf="@+id/btnValidate"/>
    <Button
            android:id="@+id/btnValidate"
            android:text="Valider"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toTopOf="@+id/textResult"/>
    <TextView
            android:id="@+id/textResult"
            tools:text="Le résultat est ici "
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toBottomOf="parent"/>


</android.support.constraint.ConstraintLayout>
.

.

2 – Création de la classe AbsFlexibleAdapter

import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.viewholders.FlexibleViewHolder

abstract class AbsFlexibleAdapter<FI : AbstractFlexibleItem<VH>, VH : FlexibleViewHolder>(items: List<FI>? = null) : FlexibleAdapter<FI>(items)
.

.

3 – Création de la classe AbsFlexibleViewHolder

import android.view.View
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder

open class AbsFlexibleViewHolder(view: View, adapter: FlexibleAdapter<out IFlexible<*>>, stickyHeader: Boolean = false) : FlexibleViewHolder(view, adapter, stickyHeader)
.

.

4 – Création de l’adapter OrderFlexibleAdapter

class OrderFlexibleAdapter(orderList: List<Order>, private val listener: OrderListener) :
    AbsFlexibleAdapter<AbstractFlexibleItem<AbsFlexibleViewHolder>, AbsFlexibleViewHolder>() {

    var orderList = orderList

    fun updateData() {
        setData(orderList)
    }

    fun setData(orderList: List<Order>) {
        val dataToDisplay = mutableListOf<AbstractFlexibleItem<AbsFlexibleViewHolder>>()

        orderList.forEach { order ->
            dataToDisplay.add(OrderFlexibleItem(order, listener))
        }

        updateDataSet(dataToDisplay)
    }

    interface OrderListener {
        fun onOrderClicked(orderId: Int)
    }
}
.

.

5 – Création de la classe OrderFlexibleItem

class OrderFlexibleItem(var order: Order, private val listener: OrderFlexibleAdapter.OrderListener) :
    AbstractFlexibleItem<AbsFlexibleViewHolder>(), FlexibleAdapter.OnItemClickListener {

    override fun bindViewHolder(
        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?,
        holder: AbsFlexibleViewHolder?,
        position: Int,
        payloads: MutableList<Any>?
    ) {
        (holder as ViewHolder).bind(order, listener)
    }

    override fun createViewHolder(
        view: View,
        adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
    ): AbsFlexibleViewHolder = ViewHolder(view, adapter)


    override fun getLayoutRes(): Int = R.layout.item_order
    override fun equals(other: Any?): Boolean = other is OrderFlexibleItem
    override fun onItemClick(view: View?, position: Int): Boolean {
        return false
    }

    class ViewHolder(view: View, adapter: FlexibleAdapter<out IFlexible<*>>) :
        AbsFlexibleViewHolder(view, adapter, false) {

        fun bind(order: Order, listener: OrderFlexibleAdapter.OrderListener) {

            contentView.setOnClickListener {
                order.id.let { orderId ->
                    listener.onOrderClicked(orderId)
                }
            }

            contentView.title.text = order.title
            contentView.subTitle.text = order.subTitle
            contentView.checkBox.isChecked = order.validate
        }
    }
}
.

Cette classe étant dépendante du fichier layout item_order.xml suivant

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="@dimen/order_view_item_height"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="@dimen/horizontal_padding"
        android:layout_marginRight="@dimen/horizontal_padding"
        android:layout_marginTop="5dp"
        android:background="@android:color/white"
        app:cardCornerRadius="4dp"
        app:cardElevation="4dp"
>

    <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <TextView
                android:id="@+id/title"
                tools:text="Commande AA-10"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="6dp"
                app:layout_constraintTop_toTopOf="parent"/>

        <TextView
                android:id="@+id/subTitle"
                tools:text="0 sac"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginLeft="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="4dp"
                app:layout_constraintTop_toBottomOf="@+id/title"/>

        <CheckBox
                android:id="@+id/checkBox"
                android:layout_width="wrap_content"
                android:layout_height="0dp"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="8dp"
                android:layout_marginRight="8dp"
                android:clickable="false"
                app:layout_constraintBottom_toBottomOf="parent"/>
    </android.support.constraint.ConstraintLayout>


</android.support.v7.widget.CardView>
.

Voici la représentation graphique de ce layout :

.

.

6 – Il ne manque que l’objet utilisé par l’adapter. Création de la classe Order.kt

class Order(var id: Int, var title: String, var subTitle: String, var validate: Boolean)
.

.

7 – Il ne faut pas oublier d’importer la librairie du flexible adapter dans le fichier build de votre application

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'com.android.support:cardview-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'

    // Utilisation FlexibleAdapter -
    implementation "eu.davidea:flexible-adapter:5.0.5"
    implementation "eu.davidea:flexible-adapter-ui:1.0.0-b5"
}