package com.ivankocijan.magicviews.views; import android.content.Context; import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; /** * MagicRecyclerView adds support for endless scrolling and empty state. * * Endless scrolling * To support endless scrolling add {@link LoadMoreDataListener}. When user scrolls down to the last item {@link @onLoadMoreData} method * will be called. If {@link loadMoreDataListner} is not set MagicRecyclerView will behave as normal RecyclerView. * * Empty state * MagicRecyclerView will show empty state out of the box if {@link emptyStateView} is set. If view is not set it will behave as normal * RecyclerView. * * @author Koc * ivan.kocijan@infinum.hr * @since 10/01/16 */ public class MagicRecyclerView extends RecyclerView { protected LoadMoreDataListener loadMoreDataListener; protected int firstVisibleItem; protected int visibleItemCount; protected int totalItemCount; private View emptyStateView; private final AdapterDataObserver observer = new AdapterDataObserver() { @Override public void onChanged() { setRecyclerViewVisibility(); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { setRecyclerViewVisibility(); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { setRecyclerViewVisibility(); } }; public MagicRecyclerView(Context context) { this(context, null); } public MagicRecyclerView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MagicRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public interface LoadMoreDataListener { void onLoadMoreData(); } protected void init() { this.addOnScrollListener(new OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //Only check scroll down if (loadMoreDataListener != null && dy > 0 && getLayoutManager() != null && getLayoutManager() instanceof LinearLayoutManager) { firstVisibleItem = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); visibleItemCount = getLayoutManager().getChildCount(); totalItemCount = getLayoutManager().getItemCount(); if ((visibleItemCount + firstVisibleItem) >= totalItemCount) { loadMoreDataListener.onLoadMoreData(); } } } }); } /** * @param listener loadMoreDataListener which notifies when user scrolls down to the last item */ public void setLoadMoreDataListener(LoadMoreDataListener listener) { this.loadMoreDataListener = listener; } @Override public void setAdapter(Adapter adapter) { final Adapter currentAdapter = getAdapter(); if (currentAdapter != null) { currentAdapter.unregisterAdapterDataObserver(observer); } super.setAdapter(adapter); if (adapter != null) { adapter.registerAdapterDataObserver(observer); } setRecyclerViewVisibility(); } /** * @param emptyState empty state view which recycler view will show when the list is empty */ public void setEmptyStateView(View emptyState) { this.emptyStateView = emptyState; setRecyclerViewVisibility(); } /** * If adapter has no items {@link emptyStateView} is shown and RecyclerView visibility is set to GONE. */ private void setRecyclerViewVisibility() { if (emptyStateView != null && getAdapter() != null) { boolean emptyViewVisible = getAdapter().getItemCount() == 0; emptyStateView.setVisibility(emptyViewVisible ? VISIBLE : GONE); setVisibility(emptyViewVisible ? GONE : VISIBLE); } } }