Instantly share code, notes, and snippets.
Created
August 31, 2015 09:33
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(1)
1
You must be signed in to fork a gist
-
Save technoir42/eb00b76f3fa7a969906f to your computer and use it in GitHub Desktop.
This file contains 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.annotation.NonNull; | |
import android.support.v7.widget.RecyclerView; | |
import android.view.ViewGroup; | |
public abstract class HeaderFooterRecyclerViewWrapperAdapter<HeaderViewHolder extends RecyclerView.ViewHolder, | |
FooterViewHolder extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | |
private static final int VIEW_TYPE_MASK = 0xfffffff; | |
private static final int VIEW_TYPE_HEADER = 0x10000000; | |
private static final int VIEW_TYPE_FOOTER = 0x20000000; | |
private final RecyclerView.Adapter wrappedAdapter; | |
private int headerItemCount; | |
private int footerItemCount; | |
private int contentItemCount; | |
public HeaderFooterRecyclerViewWrapperAdapter(@NonNull RecyclerView.Adapter wrappedAdapter) { | |
this.wrappedAdapter = wrappedAdapter; | |
wrappedAdapter.registerAdapterDataObserver(dataObserver); | |
setHasStableIds(wrappedAdapter.hasStableIds()); | |
} | |
@Override | |
public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | |
if ((viewType & VIEW_TYPE_HEADER) != 0) { | |
return onCreateHeaderItemViewHolder(parent, viewType & VIEW_TYPE_MASK); | |
} else if ((viewType & VIEW_TYPE_FOOTER) != 0) { | |
return onCreateFooterItemViewHolder(parent, viewType & VIEW_TYPE_MASK); | |
} else { | |
return wrappedAdapter.onCreateViewHolder(parent, viewType & VIEW_TYPE_MASK); | |
} | |
} | |
@Override | |
@SuppressWarnings("unchecked") | |
public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { | |
if (position < headerItemCount) { | |
onBindHeaderItemViewHolder((HeaderViewHolder)holder, position); | |
} else if (position < headerItemCount + contentItemCount) { | |
wrappedAdapter.onBindViewHolder(holder, position); | |
} else if (position < headerItemCount + contentItemCount + footerItemCount) { | |
onBindFooterItemViewHolder((FooterViewHolder)holder, position); | |
} else { | |
throw new IllegalStateException("Item position is invalid"); | |
} | |
} | |
@Override | |
public final int getItemCount() { | |
headerItemCount = getHeaderItemCount(); | |
footerItemCount = getFooterItemCount(); | |
contentItemCount = wrappedAdapter.getItemCount(); | |
return headerItemCount + contentItemCount + footerItemCount; | |
} | |
@Override | |
public final int getItemViewType(int position) { | |
if (position < headerItemCount) { | |
return (getHeaderItemViewType() & VIEW_TYPE_MASK) | VIEW_TYPE_HEADER; | |
} else if (position < headerItemCount + contentItemCount) { | |
return wrappedAdapter.getItemViewType(position) & VIEW_TYPE_MASK; | |
} else if (position < headerItemCount + contentItemCount + footerItemCount) { | |
return (getFooterItemViewType() & VIEW_TYPE_MASK) | VIEW_TYPE_FOOTER; | |
} else { | |
throw new IllegalStateException("Item position is invalid"); | |
} | |
} | |
@Override | |
public final long getItemId(int position) { | |
if (!hasStableIds()) { | |
return RecyclerView.NO_ID; | |
} | |
if (position < headerItemCount) { | |
return RecyclerView.NO_ID; // TODO: | |
} else if (position < headerItemCount + contentItemCount) { | |
return wrappedAdapter.getItemId(position); | |
} else if (position < headerItemCount + contentItemCount + footerItemCount) { | |
return RecyclerView.NO_ID; // TODO: | |
} else { | |
throw new IllegalStateException("Item position is invalid"); | |
} | |
} | |
public final void notifyHeaderItemChanged(int position) { | |
if (position < 0 || position >= headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item position " + position + " is invalid"); | |
} | |
notifyItemChanged(position); | |
} | |
public final void notifyHeaderItemRangeChanged(int positionStart, int itemCount) { | |
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item range " + positionStart + ".." + (positionStart + itemCount - 1) + " is invalid"); | |
} | |
notifyItemRangeChanged(positionStart, itemCount); | |
} | |
public final void notifyHeaderItemInserted(int position) { | |
final int headerItemCount = getHeaderItemCount(); | |
if (position < 0 || position >= headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item position " + position + " is invalid"); | |
} | |
notifyItemInserted(position); | |
} | |
public final void notifyHeaderItemRangeInserted(int positionStart, int itemCount) { | |
final int headerItemCount = getHeaderItemCount(); | |
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item range " + positionStart + ".." + (positionStart + itemCount - 1) + " is invalid"); | |
} | |
notifyItemRangeInserted(positionStart, itemCount); | |
} | |
public final void notifyHeaderItemMoved(int fromPosition, int toPosition) { | |
if (fromPosition < 0 || toPosition < 0 || fromPosition >= headerItemCount || toPosition >= headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item fromPosition " + fromPosition + " or toPosition " + toPosition + " is invalid"); | |
} | |
notifyItemMoved(fromPosition, toPosition); | |
} | |
public final void notifyHeaderItemRemoved(int position) { | |
if (position < 0 || position >= headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item position " + position + " is invalid"); | |
} | |
notifyItemRemoved(position); | |
} | |
public final void notifyHeaderItemRangeRemoved(int positionStart, int itemCount) { | |
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > headerItemCount) { | |
throw new IndexOutOfBoundsException("The specified header item range " + positionStart + ".." + (positionStart + itemCount - 1) + " is invalid"); | |
} | |
notifyItemRangeRemoved(positionStart, itemCount); | |
} | |
public final void notifyFooterItemChanged(int position) { | |
if (position < 0 || position >= footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item position " + position + " is invalid"); | |
} | |
notifyItemChanged(position + headerItemCount + contentItemCount); | |
} | |
public final void notifyFooterItemRangeChanged(int positionStart, int itemCount) { | |
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item range " + positionStart + ".." + (positionStart + itemCount - 1) + " is invalid"); | |
} | |
notifyItemRangeChanged(positionStart + headerItemCount + contentItemCount, itemCount); | |
} | |
public final void notifyFooterItemInserted(int position) { | |
final int headerItemCount = getHeaderItemCount(); | |
final int footerItemCount = getFooterItemCount(); | |
final int contentItemCount = wrappedAdapter.getItemCount(); | |
if (position < 0 || position >= footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item position " + position + " is invalid"); | |
} | |
notifyItemInserted(position + headerItemCount + contentItemCount); | |
} | |
public final void notifyFooterItemRangeInserted(int positionStart, int itemCount) { | |
final int headerItemCount = getHeaderItemCount(); | |
final int footerItemCount = getFooterItemCount(); | |
final int contentItemCount = wrappedAdapter.getItemCount(); | |
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item range " + positionStart + ".." + (positionStart + itemCount - 1) + " is invalid"); | |
} | |
notifyItemRangeInserted(positionStart + headerItemCount + contentItemCount, itemCount); | |
} | |
public final void notifyFooterItemMoved(int fromPosition, int toPosition) { | |
if (fromPosition < 0 || toPosition < 0 || fromPosition >= footerItemCount || toPosition >= footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item fromPosition " + fromPosition + " or toPosition " + toPosition + " is invalid"); | |
} | |
notifyItemMoved(fromPosition + headerItemCount + contentItemCount, toPosition + headerItemCount + contentItemCount); | |
} | |
public final void notifyFooterItemRemoved(int position) { | |
if (position < 0 || position >= footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item position " + position + " is invalid"); | |
} | |
notifyItemRemoved(position + headerItemCount + contentItemCount); | |
} | |
public final void notifyFooterItemRangeRemoved(int positionStart, int itemCount) { | |
if (positionStart < 0 || itemCount < 0 || positionStart + itemCount > footerItemCount) { | |
throw new IndexOutOfBoundsException("The specified footer item range " + positionStart + ".." + (positionStart + itemCount - 1) + " is invalid"); | |
} | |
notifyItemRangeRemoved(positionStart + headerItemCount + contentItemCount, itemCount); | |
} | |
private final RecyclerView.AdapterDataObserver dataObserver = new RecyclerView.AdapterDataObserver() { | |
@Override | |
public void onChanged() { | |
notifyDataSetChanged(); | |
} | |
@Override | |
public void onItemRangeChanged(int positionStart, int itemCount) { | |
notifyItemRangeChanged(headerItemCount + positionStart, itemCount); | |
} | |
@Override | |
public void onItemRangeInserted(int positionStart, int itemCount) { | |
notifyItemRangeInserted(headerItemCount + positionStart, itemCount); | |
} | |
@Override | |
public void onItemRangeRemoved(int positionStart, int itemCount) { | |
notifyItemRangeRemoved(headerItemCount + positionStart, itemCount); | |
} | |
@Override | |
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { | |
for (int i = 0; i < itemCount; i++) { | |
notifyItemMoved(headerItemCount + fromPosition, headerItemCount + toPosition); | |
} | |
} | |
}; | |
public int getHeaderItemCount() { | |
return 0; | |
} | |
public int getFooterItemCount() { | |
return 0; | |
} | |
public int getHeaderItemViewType() { | |
return 0; | |
} | |
public int getFooterItemViewType() { | |
return 0; | |
} | |
public HeaderViewHolder onCreateHeaderItemViewHolder(ViewGroup parent, int viewType) { | |
throw new RuntimeException("This method should be overridden in derived class"); | |
} | |
public FooterViewHolder onCreateFooterItemViewHolder(ViewGroup parent, int viewType) { | |
throw new RuntimeException("This method should be overridden in derived class"); | |
} | |
public void onBindHeaderItemViewHolder(HeaderViewHolder holder, int position) { | |
} | |
public void onBindFooterItemViewHolder(FooterViewHolder holder, int position) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment