package com.alexvasilkov.gestures.sample.demo.adapter; import android.view.ViewGroup; import android.widget.TextView; import com.alexvasilkov.android.commons.ui.Views; import com.alexvasilkov.gestures.sample.R; import java.util.List; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; abstract class DefaultEndlessRecyclerAdapter<VH extends RecyclerView.ViewHolder> extends EndlessRecyclerAdapter<RecyclerView.ViewHolder> { private static final int EXTRA_LOADING_TYPE = Integer.MAX_VALUE; private static final int EXTRA_ERROR_TYPE = Integer.MAX_VALUE - 1; private final GridLayoutManager.SpanSizeLookup spanSizes = new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int pos) { return pos == getCount() && (isLoading() || isError()) ? spanCount : originalSpanLookup == null ? 1 : originalSpanLookup.getSpanSize(pos); } }; private GridLayoutManager.SpanSizeLookup originalSpanLookup; private int spanCount; private boolean oldIsLoading; private boolean oldIsError; @Override public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == EXTRA_LOADING_TYPE) { return new LoadingViewHolder(parent); } else if (viewType == EXTRA_ERROR_TYPE) { return new ErrorViewHolder(parent, this); } else { return onCreateHolder(parent, viewType); } } protected abstract VH onCreateHolder(ViewGroup parent, int viewType); @Override public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) { onBindViewHolder(holder, position); } @SuppressWarnings("unchecked") @Override public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof LoadingViewHolder) { onBindLoadingView(((LoadingViewHolder) holder).loading); } else if (holder instanceof ErrorViewHolder) { onBindErrorView(((ErrorViewHolder) holder).error); } else { onBindHolder((VH) holder, position); } } protected abstract void onBindLoadingView(TextView loadingText); protected abstract void onBindErrorView(TextView errorText); protected abstract void onBindHolder(VH holder, int position); @Override public final int getItemViewType(int position) { if (position == getCount()) { if (isLoading()) { return EXTRA_LOADING_TYPE; } else if (isError()) { return EXTRA_ERROR_TYPE; } } int type = getViewType(position); if (type == EXTRA_LOADING_TYPE) { throw new IllegalArgumentException( "Cannot use " + EXTRA_LOADING_TYPE + " as view type"); } if (type == EXTRA_ERROR_TYPE) { throw new IllegalArgumentException("Cannot use " + EXTRA_ERROR_TYPE + " as view type"); } return type; } @SuppressWarnings({ "UnusedParameters", "WeakerAccess" }) // Public API (may be reused) protected int getViewType(int position) { return 0; } @Override protected void onLoadingStateChanged() { super.onLoadingStateChanged(); if (oldIsLoading) { if (isError()) { notifyItemChanged(getCount()); // Switching to error view } else if (!isLoading()) { notifyItemRemoved(getCount()); // Loading view is removed } } else if (oldIsError) { if (isLoading()) { notifyItemChanged(getCount()); // Switching to loading view } else if (!isError()) { notifyItemRemoved(getCount()); // Error view is removed } } else { if (isLoading() || isError()) { notifyItemInserted(getCount()); // Showing loading or error view } } oldIsError = isError(); oldIsLoading = isLoading(); } @Override public final int getItemCount() { return getCount() + (isLoading() || isError() ? 1 : 0); } public abstract int getCount(); @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { GridLayoutManager gridManager = (GridLayoutManager) recyclerView.getLayoutManager(); spanCount = gridManager.getSpanCount(); originalSpanLookup = gridManager.getSpanSizeLookup(); gridManager.setSpanSizeLookup(spanSizes); } } @Override public void onDetachedFromRecyclerView(RecyclerView recyclerView) { super.onDetachedFromRecyclerView(recyclerView); if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { GridLayoutManager gridManager = (GridLayoutManager) recyclerView.getLayoutManager(); gridManager.setSpanSizeLookup(originalSpanLookup); originalSpanLookup = null; spanCount = 1; } } private static class LoadingViewHolder extends RecyclerView.ViewHolder { final TextView loading; LoadingViewHolder(ViewGroup parent) { super(Views.inflate(parent, R.layout.demo_item_extra_loading)); loading = itemView.findViewById(R.id.extra_loading_text); } } private static class ErrorViewHolder extends RecyclerView.ViewHolder { final TextView error; ErrorViewHolder(ViewGroup parent, final EndlessRecyclerAdapter<?> adapter) { super(Views.inflate(parent, R.layout.demo_item_extra_error)); error = itemView.findViewById(R.id.extra_error); error.setOnClickListener(view -> adapter.reloadNextItemsIfError()); } } }