Skip to content

Instantly share code, notes, and snippets.

@hasankucuk
Forked from talenguyen/LoadMoreAdapter.java
Created January 5, 2019 13:17
Show Gist options
  • Save hasankucuk/5b4db84183b508aabc375440fe3b7ea1 to your computer and use it in GitHub Desktop.
Save hasankucuk/5b4db84183b508aabc375440fe3b7ea1 to your computer and use it in GitHub Desktop.
Implementation of Load More feature for RecyclerView
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public abstract class LoadMoreAdapter<T>
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int VIEW_TYPE_LOAD_MORE = 1;
private List<T> items = new ArrayList<>();
private boolean enableLoadMore;
public void setEnableLoadMore(boolean enableLoadMore) {
if (this.enableLoadMore == enableLoadMore) {
return;
}
this.enableLoadMore = enableLoadMore;
notifyDataSetChanged();
}
public void setItems(List<T> items) {
this.items.clear();
addItems(items);
}
public void addItems(List<T> items) {
this.items.addAll(items);
notifyDataSetChanged();
}
public T getItem(int position) {
if (position < 0 || position > items.size() - 1) {
return null;
}
return items.get(position);
}
@Override public int getItemCount() {
return items == null ? 0 : items.size() + (enableLoadMore ? 1 : 0);
}
@Override public int getItemViewType(int position) {
if (enableLoadMore && position == getItemCount() - 1) {
return VIEW_TYPE_LOAD_MORE;
}
return super.getItemViewType(position);
}
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_LOAD_MORE) {
return onCreateLoadMoreViewHolder(parent);
}
return onCreateItemViewHolder(parent, viewType);
}
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (!enableLoadMore || position != getItemCount() - 1) {
onBindItemViewHolder(holder, position);
}
}
public boolean isEnableLoadMore() {
return enableLoadMore;
}
public abstract RecyclerView.ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType);
public abstract void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position);
public abstract RecyclerView.ViewHolder onCreateLoadMoreViewHolder(ViewGroup parent);
}
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public abstract class OnVerticalScrollListener extends RecyclerView.OnScrollListener {
private boolean lastItemVisible;
@Override public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (!recyclerView.canScrollVertically(-1)) {
onScrolledToTop();
} else if (!recyclerView.canScrollVertically(1)) {
onScrolledToBottom();
} else if (dy < 0) {
onScrolledUp();
lastItemVisible = isLastItemVisible(recyclerView);
} else if (dy > 0) {
onScrolledDown();
boolean isLastItemVisible = isLastItemVisible(recyclerView);
if (lastItemVisible != isLastItemVisible) {
lastItemVisible = isLastItemVisible;
if (lastItemVisible) {
onScrolledDownToLastItem();
}
}
}
}
private boolean isLastItemVisible(RecyclerView recyclerView) {
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final int lastVisibleItemPosition =
((LinearLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition();
return lastVisibleItemPosition == recyclerView.getAdapter().getItemCount() - 1;
}
return false;
}
public void onScrolledDownToLastItem() {
}
public void onScrolledUp() {
}
public void onScrolledDown() {
}
public void onScrolledToTop() {
}
public void onScrolledToBottom() {
}
}
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
public class SupportLoadMoreGridLayoutManager extends GridLayoutManager {
private SpanSizeLookupWrapper spanSizeLookupWrapper;
private LoadMoreAdapter adapter;
private Runnable computeLoadMore = new Runnable() {
@Override public void run() {
final int firstCompletelyVisibleItemPosition = findFirstCompletelyVisibleItemPosition();
final int lastCompletelyVisibleItemPosition = findLastCompletelyVisibleItemPosition();
if (firstCompletelyVisibleItemPosition < 0 || lastCompletelyVisibleItemPosition < 0) {
return;
}
final boolean allVisible = firstCompletelyVisibleItemPosition == 0
&& lastCompletelyVisibleItemPosition == adapter.getItemCount() - 1;
if (allVisible) {
// All visible then we don't need to show load more
spanSizeLookupWrapper.setLoadMorePosition(-1);
} else {
spanSizeLookupWrapper.setLoadMorePosition(adapter.getItemCount() - 1);
}
adapter.setEnableLoadMore(!allVisible);
}
};;
public SupportLoadMoreGridLayoutManager(Context context, int spanCount) {
this(context, spanCount, VERTICAL, false);
}
public SupportLoadMoreGridLayoutManager(Context context, int spanCount, int orientation,
boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
spanSizeLookupWrapper = new SpanSizeLookupWrapper(spanCount);
super.setSpanSizeLookup(spanSizeLookupWrapper);
}
@Override public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) {
spanSizeLookupWrapper.setPlugIn(spanSizeLookup);
}
@Override public void onItemsChanged(final RecyclerView recyclerView) {
super.onItemsChanged(recyclerView);
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (!(adapter instanceof LoadMoreAdapter)) {
throw new IllegalArgumentException("adapter must be instance of LoadMoreAdapter");
}
this.adapter = (LoadMoreAdapter) adapter;
// Remove the old to keep only one callback execute.
recyclerView.removeCallbacks(computeLoadMore);
recyclerView.post(computeLoadMore);
}
static class SpanSizeLookupWrapper extends SpanSizeLookup {
private final int spanCount;
private SpanSizeLookup plugIn;
private int loadMorePosition = -1;
public SpanSizeLookupWrapper(int spanCount) {
this.spanCount = spanCount;
}
public void setLoadMorePosition(int loadMorePosition) {
this.loadMorePosition = loadMorePosition;
}
public void setPlugIn(SpanSizeLookup plugIn) {
this.plugIn = plugIn;
}
@Override public void invalidateSpanIndexCache() {
super.invalidateSpanIndexCache();
loadMorePosition = -1;
}
@Override public int getSpanSize(int position) {
final int spanSize;
if (loadMorePosition == position) {
spanSize = this.spanCount;
return spanSize;
} else if (plugIn != null) {
spanSize = plugIn.getSpanSize(position);
} else {
spanSize = 1;
}
return spanSize;
}
}
}
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public class SupportLoadMoreLinearLayoutManager extends LinearLayoutManager {
private LoadMoreAdapter adapter;
private Runnable computeLoadMore = new Runnable() {
@Override public void run() {
final int firstCompletelyVisibleItemPosition = findFirstCompletelyVisibleItemPosition();
final int lastCompletelyVisibleItemPosition = findLastCompletelyVisibleItemPosition();
if (firstCompletelyVisibleItemPosition < 0 || lastCompletelyVisibleItemPosition < 0) {
return;
}
final boolean allVisible = firstCompletelyVisibleItemPosition == 0
&& lastCompletelyVisibleItemPosition == adapter.getItemCount() - 1;
adapter.setEnableLoadMore(!allVisible);
}
};
public SupportLoadMoreLinearLayoutManager(Context context, int orientation,
boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override public void onItemsChanged(final RecyclerView recyclerView) {
super.onItemsChanged(recyclerView);
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (!(adapter instanceof LoadMoreAdapter)) {
throw new IllegalArgumentException("adapter must be instance of LoadMoreAdapter");
}
this.adapter = (LoadMoreAdapter) adapter;
// Remove the old to keep only one callback execute.
recyclerView.removeCallbacks(computeLoadMore);
recyclerView.post(computeLoadMore);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment