AndroidKotlin

RecyclerView – Utilisation du FlexibleAdapter avec deux items

By 12 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 utilisant deux items. Un premier article vous montrant la mise en place du flexible Adapter avec un seul item est disponible ici

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

1 – Voici l’activité principale de l’application
package fr.sebastienlaunay.kotlinflexibleadapterex2

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import fr.sebastienlaunay.kotlinflexibleadapterex2.Model.House
import fr.sebastienlaunay.kotlinflexibleadapterex2.Model.Order
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(), OrderFlexibleAdapter.OrderListener, OrderFlexibleAdapter.HouseListener {

    private var orderList = ArrayList<Order>()
    private var houseList = ArrayList<House>()
    private lateinit var listAdapter: OrderFlexibleAdapter

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

        listAdapter = OrderFlexibleAdapter(orderList, houseList, this, this)

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

        val order1 = Order(1, "Ordre 1", "Sous titre 1", false)
        val order2 = Order(2, "Ordre 2", "Sous titre 2", false)
        val order3 = Order(3, "Ordre 3", "Sous titre 3", true)
        val order4 = Order(4, "Ordre 4", "Sous titre 4", false)
        val order5 = Order(5, "Ordre 4", "Sous titre 5", true)
        val order6 = Order(6, "Ordre 6", "Sous titre 6", false)
        val order7 = Order(7, "Ordre 7", "Sous titre 7", false)

        orderList.add(order1); orderList.add(order2); orderList.add(order3); orderList.add(order4)
        orderList.add(order5); orderList.add(order6); orderList.add(order7)

        val house1 = House(1, "Maison 1", "1 pièce")
        val house2 = House(2, "Maison 2", "2 pièces")
        val house3 = House(3, "Maison 3", "3 pièces")
        val house4 = House(4, "Maison 4", "4 pièces")
        val house5 = House(5, "Maison 5", "5 pièces")

        houseList.add(house1); houseList.add(house2); houseList.add(house3); houseList.add(house4); houseList.add(house5)

        listAdapter.setOrderAndHouseData(orderList, houseList)

        btnOrder.setOnClickListener { listAdapter.updateOrderData() }
        btnHouse.setOnClickListener { listAdapter.updateHouseData() }
        btnBoth.setOnClickListener { listAdapter.updateData() }
        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
        }
        listAdapter.updateData()
    }

    override fun onHouseClicked(houseId: Int) {

        houseList.find { it.id == houseId }?.let { house ->
            textResult.text = "Vous avez cliqué sur la maison suivante : ${house.title}"
        }
    }
}

Et 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/btnOrder"
            android:text="Ordre"
            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_marginBottom="4dp"
            app:layout_constraintBottom_toTopOf="@+id/textResult"
    />
    <Button
            android:id="@+id/btnHouse"
            android:text="Maison"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dp"
            app:layout_constraintBottom_toTopOf="@+id/textResult"
            app:layout_constraintStart_toEndOf="@+id/btnOrder"
            android:layout_marginLeft="16dp" android:layout_marginStart="16dp"/>
    <Button
            android:id="@+id/btnBoth"
            android:text="LES 2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dp"
            app:layout_constraintBottom_toTopOf="@+id/textResult"
            app:layout_constraintStart_toEndOf="@+id/btnHouse" android:layout_marginLeft="16dp"
            android:layout_marginStart="16dp"/>
    <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"
            android:layout_marginBottom="4dp"
            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>, houseList: List<House>, private val orderListener: OrderListener, private val houseListener : HouseListener) :
    AbsFlexibleAdapter<AbstractFlexibleItem<AbsFlexibleViewHolder>, AbsFlexibleViewHolder>() {

    var orderList = orderList
    var houseList = houseList

    fun updateData() {
        setOrderAndHouseData(orderList,houseList)
    }

    fun updateOrderData() {
        setOrderData(orderList)
    }

    fun updateHouseData() {
        setHouseData(houseList)
    }

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

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

        updateDataSet(dataToDisplay)
    }

    fun setHouseData(houseList: List<House>) {
        val houseDataToDisplay = mutableListOf<AbstractFlexibleItem<AbsFlexibleViewHolder>>()

        houseList.forEach { house ->
            houseDataToDisplay.add(HouseFlexibleItem( house, houseListener))
        }

        updateDataSet(houseDataToDisplay)
    }

    fun setOrderAndHouseData(orderList: List<Order>, houseList: List<House>) {
        val dataToDisplay = mutableListOf<AbstractFlexibleItem<AbsFlexibleViewHolder>>()

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

        houseList.forEach { house ->
            dataToDisplay.add(HouseFlexibleItem( house, houseListener))
        }

        updateDataSet(dataToDisplay)
    }

    interface OrderListener {
        fun onOrderClicked(orderId: Int)
    }

    interface HouseListener {
        fun onHouseClicked(houseId: Int)
    }
}
5 – Création du 1er Item 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
        }
    }
}

La classe ci-dessus é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 – Création du 2eme Item HouseFlexibleItem
class HouseFlexibleItem(var house: House, private val houseListener: OrderFlexibleAdapter.HouseListener) :
    AbstractFlexibleItem<AbsFlexibleViewHolder>(), FlexibleAdapter.OnItemClickListener {

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

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

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

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

        fun bind(house: House, houseListener: OrderFlexibleAdapter.HouseListener) {

            contentView.houseTitle.text = house.title
            contentView.houseDescription.text = house.description

            contentView.setOnTouchListener { v, event ->

                if (event.action == ACTION_DOWN) {
                    v.animate().translationX(200f).setDuration(100).withEndAction {
                        v.animate().translationX(0f).duration = 100
                    }

                    house.id.let { houseId ->
                        houseListener.onHouseClicked(houseId)
                    }
                }
                true
            }
        }
    }
}

La classe ci-dessus étant dépendante du fichier layout item_order.xml suivant :

<?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="50dp">

    <View
            android:id="@+id/separator"
            android:layout_width="wrap_content"
            android:layout_height="1dp"
            android:background="@color/colorPrimary"
            android:layout_marginTop="0dp"
            app:layout_constraintTop_toTopOf="parent"/>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:orientation="horizontal"
                  android:layout_margin="8dp"
                  android:id="@+id/linearLayout"
                  android:gravity="center_vertical"
                  app:layout_constraintTop_toBottomOf="@+id/separator"
                  android:layout_marginBottom="8dp"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintStart_toStartOf="parent"
                  android:layout_marginLeft="8dp"
                  android:layout_marginStart="8dp"
                  android:layout_marginEnd="8dp"
                  app:layout_constraintEnd_toEndOf="parent"
                  android:layout_marginRight="8dp">

        <TextView
                android:id="@+id/houseTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:visibility="visible"
                tools:text="Maison 1"/>

        <TextView
                android:id="@+id/houseDescription"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:layout_marginLeft="20dp"
                android:gravity="center_vertical"
                android:visibility="visible"
                tools:text="Description de la Maison"/>
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

Voici la représentation graphique de ce layout :

7 – Il ne manque que les objets utilisés par l’adapter.

Classe Order.kt

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

Classe House.kt

class House(var id: Int, var title: String, var description: String)
8 – 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"
}

Leave a Reply