Profile Pic

Iqbal Ahmed

I develop Android Apps along with Backend
and My only LOVE is Kotlin

How to use Epoxy with ViewHolder (Part 2)

Simple Listing using Epoxy ViewHolder

3 minute read

Like in previous part we have seen how simple to list item using data class.

In this post, we gonna use View Holder to list items on RecyclerView/EpoxyRecyclerView

Listing with ViewHolder is similar like Recycler.ViewHolder but in Epoxy we extend to EpoxyModelWithHolder

2. Show List using ViewHolder

Here we need a helper class KotlinEpoxyHolder that we can get from epoxy sample or from our source code.

package com.dastnaiqbal.epoxysample.helper

import android.view.View
import com.airbnb.epoxy.EpoxyHolder
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * A pattern for easier view binding with an [EpoxyHolder]
 *
 * Se https://github.com/airbnb/epoxy/blob/2.19.0/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/helpers/KotlinEpoxyHolder.kt
 */
abstract class KotlinEpoxyHolder : EpoxyHolder() {
    private lateinit var view: View

    override fun bindView(itemView: View) {
        view = itemView
    }

    protected fun <V : View> bind(id: Int): ReadOnlyProperty<KotlinEpoxyHolder, V> =
            Lazy { holder: KotlinEpoxyHolder, prop ->
                holder.view.findViewById(id) as V?
                        ?: throw IllegalStateException("View ID $id for '${prop.name}' not found.")
            }

    /**
     * Taken from Kotterknife.
     * https://github.com/JakeWharton/kotterknife
     */
    private class Lazy<V>(
            private val initializer: (KotlinEpoxyHolder, KProperty<*>) -> V
    ) : ReadOnlyProperty<KotlinEpoxyHolder, V> {
        private object EMPTY

        private var value: Any? = EMPTY

        override fun getValue(thisRef: KotlinEpoxyHolder, property: KProperty<*>): V {
            if (value == EMPTY) {
                value = initializer(thisRef, property)
            }
            @Suppress("UNCHECKED_CAST")
            return value as V
        }
    }
}

Once we add helper class then we just need to extend our ItemVH class to KotlinEpoxyHolder and define our binding ui which we want to access

Layout itemdataclass.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent">

    <TextView
        android:id="@+id/tv"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="TextView" />
</androidx.constraintlayout.widget.ConstraintLayout>

So like we are using existing itemdataclass.xml layout, and In that we only have one textview where we want to show our text. so ItemVH binding class will be like this

class ItemVH : KotlinEpoxyHolder() {
    val tv by bind<TextView>(R.id.tv)
}

To define layout for ViewHolder we use annotation @EpoxyModelClass and our ItemViewHolder class will be extend to EpoxyModelWithHolder. and we just define our UI stuff which we want to bind or we want to show on our UI using @EpoxyAttribute annotation, so If we see we are not directly binding list item. instead we have created our own title variable to set values

@EpoxyModelClass(layout = R.layout.itemdataclass)
abstract class ItemViewHolder : EpoxyModelWithHolder<ItemVH>() {
    private val TAG = this::class.java.simpleName

    @EpoxyAttribute
    lateinit var title: String

    override fun bind(view: ItemVH) {
        super.bind(view)
        view.tv.text = title
    }
}

Once our ItemViewHolder class ready then we can directly use it in Controller. Creating controller, it’s same like previous example

Epoxy Controller: SimpleViewHolderController.kt

class SimpleViewHolderController : TypedEpoxyController<List<String>>() {

    override fun buildModels(data: List<String>?) {
        data?.forEachIndexed { index, s ->
            itemViewHolder {
                id(index)
                title(s)
            }
        }
    }
}

And the last step to attach controller in Epoxy Recyclerview

MainActivity.kt

package com.dastnaiqbal.epoxysample

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.dastnaiqbal.epoxysample.dataclass.SimpleDataController
import com.dastnaiqbal.epoxysample.viewholder.SimpleViewHolderController
import kotlinx.android.synthetic.main.activity_main.*

/**
 *
 * "Iqbal Ahmed" created on 22/08/2020
 */

class MainActivity : AppCompatActivity() {
    private val dataClassController by lazy {
        SimpleDataController()
    }

    private val viewHolderController by lazy {
        SimpleViewHolderController()
    }

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

        /**
         * Listing using Data Clas
         */
//        rv.adapter = dataClassController.adapter
//        dataClassController.setData(ArrayList<String>().apply {
//            repeat(10) {
//                add("Item Data Class #$it")
//            }
//        })

        /**
         * Listing using ViewHolder
         */
        rv.adapter = viewHolderController.adapter
        viewHolderController.setData(ArrayList<String>().apply {
            repeat(10) {
                add("Item View Holder #$it")
            }
        })
    }
}

Congratulations You populated your list in Epoxy using ViewHolder

In this post, we used Kotlin ViewHolder as an Epoxy Model and Simple Controller,

In the Next post, we gonna use Databinding as an Epoxy Model and Instead of creating a separate adapter, we gonna use extension method to populate data on Epoxy RecyclerView.

SourceCode Link: https://github.com/DastanIqbal/EpoxySample/tree/epoxy/viewholder

Happy Coding !!

Say something

Comments

Nothing yet.

Recent posts

Categories

About

I develop Android Apps along with Backend
and My only LOVE is Kotlin