Android Pagination Tutorial—Handling Multiple View Types

Pagination is also known as endless or infinite scrolling. This is achieved using RecyclerView. In this tutorial, I’ll show you how to paginate when multiple View Types are involved.

Welcome to part 4 of the Android Pagination Tutorial Series!

Previously in part 3, we identified various scenarios in which errors can occur. Then, we saw how to handle these Pagination errors via code and present them to users.

RecyclerView is well known for supporting multiple view types. What if you wanted to do that and paginate the list, at the same time? Let’s look at just that, in this tutorial.

This article has been updated for AndroidX!

Android Pagination Series Overview

  1. Getting Started with RecyclerView
  2. Pagination with APIs using Retrofit and Gson
  3. Error Handling
  4. Using Multiple RecyclerView Types
  5. Adding Swipe-to-Refresh Support

NOTE: This is a continuation of the Pagination series. Hence this article (code included) assumes that you’ve read and implemented what was discussed in the previous parts.

If you’re new, I strongly suggest you start with Part 1 — Implementing the Pagination logic. Otherwise, if you think you’re good, read on!

Supporting Multiple View Types in RecyclerView

Often, when you want to display a list, all the items aren’t the same. Commonly, your first item might be a hero image, followed by a list.

We all know too well that when multiple View Types are involved, the code tends to get verbose. Additionally, with Pagination in play, things are about to get ugly.

However, that doesn’t have to be the case. Code complexity should not scare you. Provided you spend little time organizing your codebase.

If you remember from the previous tutorials, we already have 2 view types in our RecyclerView.

  1. The regular list item
  2. Loading footer

But the loading footer is only temporary, it briefly appears until the next page loads. After that, it disappears.

So let’s go ahead and add a third View type — a Hero image as the first item in the list.

What we’ll be creating

Creating the Hero ViewHolder

Adding a new View Type is a simple thing to do. If you’re familiar with RecyclerView, you should know this by now as well.

I strongly encourage you to create your own, without referencing this section. However, if you need help, I’ve got your back!

There’s no set way to go about it, but here are the steps:

  1. Create XML layout for your new View
  2. Update Item View Types
  3. Create it’s ViewHolder in RecyclerView
  4. Bind the View

Just 3 simple steps. Let’s start with 1.

1. Create XML Layout for new View Type

Create a new XML file res/layout/item_hero.xml.

As mentioned above, we will create a header for our list. Mine looks like this.

Hero Layout preview

Feel free to use your creativity to make a layout you like. But if you want to use mine, you can get the layout file from GitHub.

2. Update Item View Types

Once your layout is created, we need to tell RecyclerView about it. Open PaginationAdapter.java and add a flag for our new (header) view type.

public class PaginationAdapter extends RecyclerView.Adapter < RecyclerView.ViewHolder > {

 // View Types
 private static final int ITEM = 0;
 private static final int LOADING = 1;
 private static final int HERO = 2;
 ...
}

Next, we need to tell our Adapter about which View should be displayed when. You do this in the getItemViewType() method.

 @Override
 public int getItemViewType(int position) {
  if (position == 0) {
   return HERO;
  } else {
   return (position == movieResults.size() - 1 && isLoadingAdded) ?
    LOADING : ITEM;
  }
 }

3. Create ViewHolder in RecyclerView

Start by creating an inner class for your ViewHolder in PaginationAdapter.

/**
 * Header ViewHolder
 */
protected class HeroVH extends RecyclerView.ViewHolder {
 private TextView mMovieTitle;
 private TextView mMovieDesc;
 private TextView mYear;
 private ImageView mPosterImg;

 public HeroVH(View itemView) {
  super(itemView);
  // init views
  mMovieTitle = (TextView) itemView.findViewById(R.id.movie_title);
  mMovieDesc = (TextView) itemView.findViewById(R.id.movie_desc);
  mYear = (TextView) itemView.findViewById(R.id.movie_year);
  mPosterImg = (ImageView) itemView.findViewById(R.id.movie_poster);
 }
}

With the ViewHolder created, we need to inflate it in onCreateViewHolder().

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 RecyclerView.ViewHolder viewHolder = null;
 LayoutInflater inflater = LayoutInflater.from(parent.getContext());

 switch (viewType) {
  case HERO:
   View viewHero = inflater.inflate(R.layout.item_hero, parent, false);
   viewHolder = new HeroVH(viewHero);
   break;
   ...
 }
 return viewHolder;
}

4. Bind the View

Now that our header ViewHolder is created, it’s time to bind it. From the name, you would’ve known what I’m talking about. Yes, the onBindViewHolder() method!

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 Result result = movieResults.get(position); // Movie

 switch (getItemViewType(position)) {

  case HERO:
   final HeroVH heroVh = (HeroVH) holder;

   heroVh.mMovieTitle.setText(result.getTitle());
   heroVh.mYear.setText(formatYearLabel(result));
   heroVh.mMovieDesc.setText(result.getOverview());

   loadImage(result.getBackdropPath())
    .into(heroVh.mPosterImg);
   break;
   ...
 }
}

// Bind method helpers

private String formatYearLabel(Result result) {
 return result.getReleaseDate().substring(0, 4) // we want the year only
  +
  " | " +
  result.getOriginalLanguage().toUpperCase();
}

private RequestBuilder < Drawable > loadImage(@NonNull String posterPath) {
 return GlideApp
  .with(context)
  .load(BASE_URL_IMG + posterPath)
  .centerCrop();
}

That’s all there is to it! That wasn’t as complex as you thought, was it? We already have 2 different View Types in play. We just added a third one.

The pagination logic wasn’t touched. So everything will work as it did, with the addition of a header View.

Don’t take my word though. Find out yourself with the output below!


Output — Final Result

Get the Source Code

View Project on GitHub

The key to implementing any successful feature comes down to the basics. It’s the foundation. In the case of Pagination, it came down to implementing the Pagination logic correctly. Once that was done, add-on features were relatively easy to add. Like multiple View Types!

I hope with this tutorial, you’ll be able to paginate lists with different View Types.

What do you plan to create? Does this cover your use-cases? Tell me in the comments below.

Lastly, if you loved reading this article, share it with others so they can learn too!

Suleiman

Product Designer who occasionally writes code.

You may also like...

9 Responses

  1. Thanks for sharing nice tutorial on Android Pagination

  2. earlyman says:

    good work, you really helped me

  3. This Seriously Awesome & Educational article I have ever come across

    keep writing more educative content.

  4. Kian Asher says:

    I am searching for this sort of article. Much obliged for the valuable data.

  5. Binod says:

    You really are hero. Thanks for your hardworking.

  6. Natisha says:

    I am looking for this type of article. Thanks for the useful info.

  7. Josie says:

    This is the best article I have read. Thanks for sharing.

  8. yun says:

    Android Pagination Series Overview links are broken. You should change http to https.

  9. Salemsky95 says:

    Hello Senior Suleiman19 Did you post the Adding Swipe-to-Refresh Support part of the series yet, I was thinking would be great to create a detail view on click of each of the card. Would be lovely. Please kindly consider making it. Love Ya work!

Leave a Reply

Your email address will not be published. Required fields are marked *