We will do the same effect using the same technique what we did with ListViews. The only difference is that RecyclerViews don’t have footers so we need to use two different ViewHolders. But that was my problem to figure out, you can just copy and paste my code.
ADD dependency recycleviews and cardview.
compile 'com.android.support:appcompat-v7:25.0.0' compile 'com.android.support:recyclerview-v7:25.0.0'
Create Layout activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.suleiman.pagination.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/main_recycler" android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" android:paddingBottom="@dimen/activity_margin_content" android:paddingTop="@dimen/activity_margin_content"/> <ProgressBar android:id="@+id/main_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"/> </FrameLayout>
Create new layout item_list.xml
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/item_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_margin_half" android:layout_marginEnd="@dimen/activity_horizontal_margin" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_marginRight="@dimen/activity_horizontal_margin" android:layout_marginStart="@dimen/activity_horizontal_margin" android:layout_marginTop="@dimen/activity_margin_half" android:background="@android:color/white" android:padding="@dimen/activity_horizontal_margin" tools:text="Title 12"/>
Create layout for progress item_progress.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"> <ProgressBar android:id="@+id/loadmore_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"/> </FrameLayout>
Add this to MainActivity.java
package org.osworld.androidosworld; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.widget.ProgressBar; import org.osworld.androidosworld.PaginationScrollListener; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; PaginationAdapter adapter; LinearLayoutManager linearLayoutManager; RecyclerView rv; ProgressBar progressBar; private static final int PAGE_START = 0; private boolean isLoading = false; private boolean isLastPage = false; private int TOTAL_PAGES = 3; private int currentPage = PAGE_START; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rv = (RecyclerView) findViewById(R.id.main_recycler); progressBar = (ProgressBar) findViewById(R.id.main_progress); adapter = new PaginationAdapter(this); linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); rv.setLayoutManager(linearLayoutManager); rv.setItemAnimator(new DefaultItemAnimator()); rv.setAdapter(adapter); rv.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) { @Override protected void loadMoreItems() { isLoading = true; currentPage += 1; // mocking network delay for API call new Handler().postDelayed(new Runnable() { @Override public void run() { loadNextPage(); } }, 1000); } @Override public int getTotalPageCount() { return TOTAL_PAGES; } @Override public boolean isLastPage() { return isLastPage; } @Override public boolean isLoading() { return isLoading; } }); // mocking network delay for API call new Handler().postDelayed(new Runnable() { @Override public void run() { loadFirstPage(); } }, 1000); } private void loadFirstPage() { Log.d(TAG, "loadFirstPage: "); List<Movie> movies = Movie.createMovies(adapter.getItemCount()); progressBar.setVisibility(View.GONE); adapter.addAll(movies); if (currentPage <= TOTAL_PAGES) adapter.addLoadingFooter(); else isLastPage = true; } private void loadNextPage() { Log.d(TAG, "loadNextPage: " + currentPage); List<Movie> movies = Movie.createMovies(adapter.getItemCount()); adapter.removeLoadingFooter(); isLoading = false; adapter.addAll(movies); if (currentPage != TOTAL_PAGES) adapter.addLoadingFooter(); else isLastPage = true; } }
Create For Movie Models Movie.java
package org.osworld.androidosworld; import java.util.ArrayList; import java.util.List; /** * Created by OSWORLD on 19/10/16. */ public class Movie { private String title; public Movie() { } public Movie(String title) { this.title = title; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } /** * Creating 10 dummy content for list. * * @param itemCount * @return */ public static List<Movie> createMovies(int itemCount) { List<Movie> movies = new ArrayList<>(); for (int i = 0; i < 10; i++) { Movie movie = new Movie("Movie " + (itemCount == 0 ? (itemCount + 1 + i) : (itemCount + i))); movies.add(movie); } return movies; } }
Create New Class Java PaginationAdapter.java
package org.osworld.androidosworld; import android.content.Context; import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.ArrayList; import java.util.List; /** * Created by OSWORLD on 05/10/17. */ public class PaginationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final int ITEM = 0; private static final int LOADING = 1; private List<Movie> movies; private Context context; private boolean isLoadingAdded = false; public PaginationAdapter(Context context) { this.context = context; movies = new ArrayList<>(); } public List<Movie> getMovies() { return movies; } public void setMovies(List<Movie> movies) { this.movies = movies; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder viewHolder = null; LayoutInflater inflater = LayoutInflater.from(parent.getContext()); switch (viewType) { case ITEM: viewHolder = getViewHolder(parent, inflater); break; case LOADING: View v2 = inflater.inflate(R.layout.item_progress, parent, false); viewHolder = new LoadingVH(v2); break; } return viewHolder; } @NonNull private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) { RecyclerView.ViewHolder viewHolder; View v1 = inflater.inflate(R.layout.item_list, parent, false); viewHolder = new MovieVH(v1); return viewHolder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { Movie movie = movies.get(position); switch (getItemViewType(position)) { case ITEM: MovieVH movieVH = (MovieVH) holder; movieVH.textView.setText(movie.getTitle()); break; case LOADING: // Do nothing break; } } @Override public int getItemCount() { return movies == null ? 0 : movies.size(); } @Override public int getItemViewType(int position) { return (position == movies.size() - 1 && isLoadingAdded) ? LOADING : ITEM; } /* Helpers _________________________________________________________________________________________________ */ public void add(Movie mc) { movies.add(mc); notifyItemInserted(movies.size() - 1); } public void addAll(List<Movie> mcList) { for (Movie mc : mcList) { add(mc); } } public void remove(Movie city) { int position = movies.indexOf(city); if (position > -1) { movies.remove(position); notifyItemRemoved(position); } } public void clear() { isLoadingAdded = false; while (getItemCount() > 0) { remove(getItem(0)); } } public boolean isEmpty() { return getItemCount() == 0; } public void addLoadingFooter() { isLoadingAdded = true; add(new Movie()); } public void removeLoadingFooter() { isLoadingAdded = false; int position = movies.size() - 1; Movie item = getItem(position); if (item != null) { movies.remove(position); notifyItemRemoved(position); } } public Movie getItem(int position) { return movies.get(position); } /* View Holders _________________________________________________________________________________________________ */ /** * Main list's content ViewHolder */ protected class MovieVH extends RecyclerView.ViewHolder { private TextView textView; public MovieVH(View itemView) { super(itemView); textView = (TextView) itemView.findViewById(R.id.item_text); } } protected class LoadingVH extends RecyclerView.ViewHolder { public LoadingVH(View itemView) { super(itemView); } } }
Create New Class PaginationScrollListener.java
package org.osworld.androidosworld; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; /** * Pagination * Created by OSWORLD on 05/15/17. */ public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener { LinearLayoutManager layoutManager; /** * Supporting only LinearLayoutManager for now. * * @param layoutManager */ public PaginationScrollListener(LinearLayoutManager layoutManager) { this.layoutManager = layoutManager; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int visibleItemCount = layoutManager.getChildCount(); int totalItemCount = layoutManager.getItemCount(); int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); if (!isLoading() && !isLastPage()) { if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount && firstVisibleItemPosition >= 0 && totalItemCount >= getTotalPageCount()) { loadMoreItems(); } } } protected abstract void loadMoreItems(); public abstract int getTotalPageCount(); public abstract boolean isLastPage(); public abstract boolean isLoading(); }