Android and Kotlin: RecyclerView with multiple view types
Here our goal is prepare a RecyclerView Adapter to accept different type of data and represent them into view according to there data model
With the help of Kotlin, it becomes easy to resolve this problem.
Step 1:
Let’s create our data structure 1st. Here we used sealed class and data class(to hold the data mainly with some build in benefits from Kotlin).
Sealed classes and interfaces represent restricted class hierarchies that provide more control over inheritance. All direct subclasses of a sealed class are known at compile time.
sealed class DataModel {
data class Header(
@ColorInt val bgColor: Int,
val title: String
) : DataModel() data class Family(
val name: String,
val relationship: String
) : DataModel() data class Friend(
val name: String,
val gender: String
) : DataModel() data class Colleague(
val name: String,
val organization: String,
val designation: String
) : DataModel()
}
Step 2:
Create the viewHolder class with Kotlin and sealed class magic:
class DataAdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private fun bindFamily(item: DataModel.Family) {
//Do your view assignment here from the data model
TODO()
} private fun bindFriend(item: DataModel.Friend) {
TODO()
} private fun bindColleague(item: DataModel.Colleague) {
TODO()
} private fun bindHeader(item: DataModel.Header) {
//Do your view assignment here from the data model
TODO()
} fun bind(dataModel: DataModel) {
when (dataModel) {
is DataModel.Family -> bindFamily(dataModel)
is DataModel.Friend -> bindFriend(dataModel)
is DataModel.Colleague -> bindColleague(dataModel)
is DataModel.Header -> bindHeader(dataModel)
}
}
}
Here, Its a simple custom viewHoder class, where we can bind our views with data according the type
Step 3:
So now we will create our adapter class where we mainly need to override these functions:
onCreateViewHolder : inflate layout with view holder
onBindViewHolder : bind view with data model
getItemCount : which will return total view number which have to render
getItemViewType : here we have to return different int value based on our different data model which we can use at onCreateViewHolder method.
class DataAdapter : RecyclerView.Adapter<DataAdapter.DataAdapterViewHolder>() {
private val adapterData = mutableListOf<DataModel>()
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): DataAdapterViewHolder {
val layout = when (viewType) {
TYPE_FAMILY -> R.layout.item_family
TYPE_FRIEND -> R.layout.item_friend
TYPE_COLLEAGUE -> R.layout.item_colleague
TYPE_HEADER -> R.layout.item_header
else -> throw IllegalArgumentException("Invalid type")
}
val view = LayoutInflater
.from(parent.context)
.inflate(layout, parent, false)
return DataAdapterViewHolder(view)
}
override fun onBindViewHolder(
holder: DataAdapterViewHolder,
position: Int
) {
holder.bind(adapterData[position])
}
override fun getItemCount(): Int = adapterData.size
override fun getItemViewType(position: Int): Int {
return when (adapterData[position]) {
is DataModel.Family -> TYPE_FAMILY
is DataModel.Friend -> TYPE_FRIEND
is DataModel.Colleague -> TYPE_COLLEAGUE
else -> TYPE_HEADER
}
}
fun setData(data: List<DataModel>) {
adapterData.apply {
clear()
addAll(data)
}
}
companion object {
private const val TYPE_FAMILY = 0
private const val TYPE_FRIEND = 1
private const val TYPE_COLLEAGUE = 2
private const val TYPE_HEADER = 3
}
}
Final step:
Now actually you do not need to do anything else. Just complete your adapter implementation as normal adapter. And set your DataAdapter.setData() from your view and your will see different types of view-holder according to your data set!
private val dataAdapter: DataAdapter by lazy {
DataAdapter()
}.....
dataAdapter.setData(getMockData())findViewById<RecyclerView>(R.id.recyclerView)
.apply {
layoutManager = LinearLayoutManager(this@MainActivity)
hasFixedSize()
this.adapter = dataAdapter
}
Full code: https://github.com/ivancse58/recyclerviewwithmultipletypes
Hope it will help you. Cheers!!