RecyclerView With Multiple View Types
Today we are going to discuss that how to display RecyclerView With Multiple View Types. Let’s take an example of any scrollable list where we want to display some items with video content and some with image content. Or another example like a we want to display static header and footer in scrollable list. In both of the example we can integrate RecyclerView with multiple viewtypes.
To implement RecyclerView with multiple viewtypes (heterogeneous layouts), most of the work is done within the RecyclerView.Adapter
. In particular, there are special methods to be overridden within the adapter:
- getViewType()
- onCreateViewHolder()
- onBindViewHolder()
Before i start with example i have consider several points
- I should be able to reuse cell in another RecyclerView.
- I should able to integrate another cell types into RecyclerView.
Implementation
Step 1:
Add following dependencies into build.gradle file.
dependencies {
implementation 'com.android.support:recyclerview-v7:28.0.0-rc01'
implementation 'com.github.bumptech.glide:glide:4.7.1'
}
Step 2:
Now create different ViewHolder class for Header, Footer and for display MovieList. Extend those classes with RecyclerView.ViewHolder
.
HeaderViewHolder.kt
package com.android4dev.recyclerview.adapter
import android.support.v7.widget.RecyclerView
import android.view.View
import kotlinx.android.synthetic.main.list_item_recycler_header.view.*
class HeaderViewHolder(itemView:View):RecyclerView.ViewHolder(itemView) {
fun bindView(){
itemView.textHeader.text="Header Section"
}
}
FooterViewHolder.kt
package com.android4dev.recyclerview.adapter
import android.support.v7.widget.RecyclerView
import android.view.View
import kotlinx.android.synthetic.main.list_item_recycler_header.view.*
class FooterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindView() {
itemView.textHeader.textHeader.text = "Footer Section"
}
}
MovieListViewHolder.kt
package com.android4dev.recyclerview.adapter
import android.support.v7.widget.RecyclerView
import android.view.View
import com.android4dev.recyclerview.model.MovieModel
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.list_item_movie.view.*
import java.util.*
class MovieListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindView(movieModel: MovieModel) {
itemView.textMovieTitle.text = movieModel.movieTitle
itemView.textMovieViews.text = "Views: " + movieModel.movieViews
itemView.textReleaseDate.text = "Release Date: " + movieModel.releaseDate
Glide.with(itemView.context).load(movieModel.moviePicture!!).into(itemView.imageMovie)
}
}
Step 3:
Make a layout files for HeaderViewHolder, FooterViewHolder and MovieListViewHolder.
list_item_recycler_header.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:fontFamily="sans-serif-condensed"
android:gravity="center"
android:padding="16dp"
android:text="Header Section"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold" />
</android.support.constraint.ConstraintLayout>
list_item_movie.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="wrap_content"
android:background="@android:color/white">
<ImageView
android:id="@+id/imageMovie"
android:layout_width="110dp"
android:layout_height="150dp"
android:contentDescription="@string/app_name"
android:scaleType="fitXY"
android:src="@drawable/ic_avengers" />
<TextView
android:id="@+id/textMovieTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingStart="16dp"
android:textColor="@android:color/black"
android:textSize="20sp"
app:layout_constraintStart_toEndOf="@id/imageMovie"
tools:text="Avengers" />
<TextView
android:id="@+id/textMovieViews"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingStart="16dp"
android:textColor="@android:color/black"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="@id/imageMovie"
app:layout_constraintTop_toBottomOf="@id/textMovieTitle"
tools:text="Views: 100" />
<TextView
android:id="@+id/textReleaseDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingStart="16dp"
android:textColor="@android:color/black"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="@id/imageMovie"
app:layout_constraintTop_toBottomOf="@id/textMovieViews"
tools:text="Release Date: 16 Feb 2018" />
</android.support.constraint.ConstraintLayout>
Step 4:
Now create one Adapter class called MovieListHeaderAdapter and extend it using RecyclerView.Adapter
.
package com.android4dev.recyclerview.adapter
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import com.android4dev.recyclerview.R
import com.android4dev.recyclerview.model.MovieModel
class MovieListHeaderAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var listOfMovies = listOf<MovieModel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
CellType.HEADER.ordinal -> HeaderViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_recycler_header, parent, false))
CellType.CONTENT.ordinal -> MovieListViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_movie, parent, false))
CellType.FOOTER.ordinal -> FooterViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_recycler_header, parent, false))
else -> MovieListViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_movie, parent, false))
}
}
override fun getItemCount(): Int = listOfMovies.size + 2
//add 2 size in itemcount because we are going to add header and footer cell in list
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
CellType.HEADER.ordinal -> {
val headerViewHolder = holder as HeaderViewHolder
headerViewHolder.bindView()
}
CellType.CONTENT.ordinal -> {
val headerViewHolder = holder as MovieListViewHolder
headerViewHolder.bindView(listOfMovies[position - 1])
}
CellType.FOOTER.ordinal -> {
val footerViewHolder = holder as FooterViewHolder
footerViewHolder.bindView()
}
}
}
/***
* This method will return cell type base on position
*/
override fun getItemViewType(position: Int): Int {
return when (position) {
0 -> CellType.HEADER.ordinal
listOfMovies.size + 1 -> CellType.FOOTER.ordinal
else -> CellType.CONTENT.ordinal
}
}
/***
* Enum class for recyclerview Cell type
*/
enum class CellType(viewType: Int) {
HEADER(0),
FOOTER(1),
CONTENT(2)
}
fun setMovieList(listOfMovies: List<MovieModel>) {
this.listOfMovies = listOfMovies
notifyDataSetChanged()
}
}
In above Adapter class we have one enum class for different viewtypes.
enum class CellType(viewType: Int) {
HEADER(0),
FOOTER(1),
CONTENT(2)
}
getItemViewType() will return celltype according to position. In above Adapter class we will return HEADER view type for adapter’s 0 position, FOOTER view type for listOfMovies.size + 1 adapter’s position, CONTENT view type for all other remaining positions.
In onCreateViewHolder() class we will inflate different layouts depends upon getItemViewType() value.
In a same way we will call different ViewHolder classes depends upon getItemViewType(position) value.
Step 5:
Make Activity class called RecyclerViewHeaderFooterActivity and add following code into it.
package com.android4dev.recyclerview
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import com.android4dev.recyclerview.adapter.MovieListAdapter
import com.android4dev.recyclerview.adapter.MovieListHeaderAdapter
import com.android4dev.recyclerview.base.BaseActivity
import com.android4dev.recyclerview.model.MovieModel
import com.android4dev.recyclerview.recyclerview_helper.DividerItemDecoration
import com.android4dev.recyclerview.recyclerview_helper.VerticalSpaceItemDecoration
import kotlinx.android.synthetic.main.activity_main.*
class RecyclerViewHeaderFooterActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
}
private fun initView() {
recyclerViewMovies.layoutManager = LinearLayoutManager(this)
recyclerViewMovies.addItemDecoration(VerticalSpaceItemDecoration(48))
//This will for default android divider
recyclerViewMovies.addItemDecoration(DividerItemDecoration(this))
//This will for custom divider
// recyclerViewMovies.addItemDecoration(DividerItemDecoration(this, R.drawable.drawable_divider_view))
val movieListAdapter = MovieListHeaderAdapter()
recyclerViewMovies.adapter = movieListAdapter
movieListAdapter.setMovieList(generateDummyData())
}
private fun generateDummyData(): List<MovieModel> {
val listOfMovie = mutableListOf<MovieModel>()
var movieModel = MovieModel(1, "Avengers", 500, "16 Feb 2018", R.drawable.ic_avengers)
listOfMovie.add(movieModel)
movieModel = MovieModel(2, "Avengers: Age of Ultron", 400, "17 March 2018", R.drawable.ic_avengers_2)
listOfMovie.add(movieModel)
movieModel = MovieModel(3, "Iron Man 3", 550, "17 April 2018", R.drawable.ic_ironman_3)
listOfMovie.add(movieModel)
movieModel = MovieModel(4, "Avengers: Infinity War", 1500, "15 Jan 2018", R.drawable.ic_avenger_five)
listOfMovie.add(movieModel)
movieModel = MovieModel(5, "Thor: Ragnarok", 200, "17 March 2018", R.drawable.ic_thor)
listOfMovie.add(movieModel)
movieModel = MovieModel(6, "Black Panther", 250, "17 May 2018", R.drawable.ic_panther)
listOfMovie.add(movieModel)
movieModel = MovieModel(7, "Logan", 320, "17 Dec 2018", R.drawable.ic_logan)
listOfMovie.add(movieModel)
return listOfMovie
}
}
Step 6:
Create layout file for Activity class.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
android:background="@android:color/white"
tools:context=".RecyclerViewLinearLayoutActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerViewMovies"
android:layout_width="0dp"
android:layout_height="0dp"
android:overScrollMode="never"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Step 7:
Now create two more classes for ItemDecoration.
VerticalSpaceItemDecoration.kt
package com.android4dev.recyclerview.recyclerview_helper
import android.graphics.Rect
import android.support.v7.widget.RecyclerView
import android.view.View
/***
* Made by Lokesh Desai (Android4Dev)
*/
class VerticalSpaceItemDecoration(private val verticalSpaceHeight: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State) {
outRect.bottom = verticalSpaceHeight
}
}
DividerItemDecoration.kt
package com.android4dev.recyclerview.recyclerview_helper
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.support.v4.content.ContextCompat
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.drawable.Drawable
/***
* Made by Lokesh Desai (Android4Dev)
*/
class DividerItemDecoration
/**
* Default divider will be used
*/(context: Context) : RecyclerView.ItemDecoration() {
private val ATTRS = intArrayOf(android.R.attr.listDivider)
private var divider: Drawable? = null
init {
val styledAttributes = context.obtainStyledAttributes(ATTRS)
divider = styledAttributes.getDrawable(0)
styledAttributes.recycle()
}
/**
* Custom divider will be used
*/
constructor(context: Context, resId: Int) : this(context) {
divider = ContextCompat.getDrawable(context, resId)
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val left = parent.paddingLeft
val right = parent.width - parent.paddingRight
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val params = child.layoutParams as RecyclerView.LayoutParams
val top = child.bottom + params.bottomMargin
val bottom = top + divider!!.intrinsicHeight
divider!!.setBounds(left, top, right, bottom)
divider!!.draw(c)
}
}
}
Above both classes will help us to add Dividers and Proper Spacing between all the Grid Items.
Now Run the project and wait for the result.
Conclusion
With small amount of effort we can successfully integrate RecyclerView with Multiple View Types. All we have to do is create different ViewHolders classes for different CellType.
Source Code
Check out Github Project Which Contains All RecyclerView Examples
You Can Also Refer
- How to integrate RecyclerView With LinearLayoutManager?
- How to integrate RecyclerView With GridLayoutManager?
- How to integrate RecyclerView With StaggeredGridLayoutManager?

Lokesh Desai
Related posts
6 Comments
Leave a Reply Cancel reply
Subscribe
* You will receive the latest news and updates on your favorite celebrities!
Quick Cook!
How to use Data Class in Kotlin?
In this blog, you will learn about How to use Data Class in Kotlin? and What is Data Class? Tired…
Android Kotlin Tutorial: How to create a Class and Object ?
Today we are going to learn How to Create a Class and Object in Kotlin. Kotlin is an Object Oriented…
[…] How to integrate RecyclerView With Multiple Views (Header & Footer)? […]
[…] How to integrate RecyclerView With Multiple Views (Header & Footer)? […]
Nicely explained thank you for hard work
Nice explanation. thanks
Good info. Lucky me I reach on your website by accident, I bookmarked it.
A powerful share, I just given this onto a colleague who was doing a little analysis on this. And he in reality bought me breakfast as a result of I discovered it for him.. smile. So let me reword that: Thnx for the deal with! But yeah Thnkx for spending the time to debate this, I feel strongly about it and love studying more on this topic. If attainable, as you develop into experience, would you thoughts updating your blog with more details? It is highly useful for me. Large thumb up for this blog submit!