Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save technoir42/eb00b76f3fa7a969906f to your computer and use it in GitHub Desktop.
Save technoir42/eb00b76f3fa7a969906f to your computer and use it in GitHub Desktop.
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