-
-
Save hasankucuk/5b4db84183b508aabc375440fe3b7ea1 to your computer and use it in GitHub Desktop.
Implementation of Load More feature for RecyclerView
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() { | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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