Skip to content

Instantly share code, notes, and snippets.

@iamMehedi
Created March 27, 2017 09:08
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamMehedi/28e846bf498056d50132fb1d58846d36 to your computer and use it in GitHub Desktop.
Save iamMehedi/28e846bf498056d50132fb1d58846d36 to your computer and use it in GitHub Desktop.
A Generic RecyclerView adapter implementation that can be used everywhere with any kind of RecyclerView items
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Mehedi on 5/31/15.
*
* A Generic Adapter for RecyclerView
*/
public class GenericRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
/**
* Maps the type of item with the position of such an item
*/
SparseArray<Integer> mViewTypeMap;
/**
* Stores the items
*/
List<RecyclableViewItem> mDataStore;
protected onItemClickListener mItemClickListener;
/**
*
* @param data list of items
*/
public GenericRecycleAdapter(List<RecyclableViewItem> data){
super();
mDataStore = data;
generateViewTypeMapping();
}
/**
*
* @param data list of items
* @param itemClickListener listener for item click events
*/
public GenericRecycleAdapter(List<RecyclableViewItem> data, onItemClickListener itemClickListener)
{
this(data);
mItemClickListener = itemClickListener;
}
/**
* Generate the mapping for all types of item
*/
private void generateViewTypeMapping(){
mViewTypeMap = new SparseArray<Integer>();
if(mDataStore != null && !mDataStore.isEmpty())
{
int position = 0;
for(RecyclableViewItem item : mDataStore)
{
addMappingForItem(item, position);
position++;
}
}
}
/**
*
* @param item list item
* @param position position of the item
*/
private void addMappingForItem(RecyclableViewItem item, int position)
{
if(mViewTypeMap.indexOfKey(item.getViewType()) < 0)
{
mViewTypeMap.put(item.getViewType(), position);
}
}
/**
* Add an item at the end/bottom
* @param item
*/
public void appendItem(RecyclableViewItem item){
if(mDataStore == null)
{
mDataStore = new ArrayList<RecyclableViewItem>();
}
int index = mDataStore.size();
mDataStore.add(item);
addMappingForItem(item, index);
notifyItemInserted(index);
}
/**
* Add an item at a given position
* @param item
* @param position
*/
public void addItemAtPosition(RecyclableViewItem item, int position)
{
if(mDataStore == null)
{
mDataStore = new ArrayList<RecyclableViewItem>();
}
mDataStore.add(position, item);
generateViewTypeMapping();
notifyItemInserted(position);
}
/**
* Remove the item at given position
* @param position
* @return the item that was removed
*/
public RecyclableViewItem removeItemAtPosition(int position)
{
RecyclableViewItem item = null;
if(mDataStore != null && mDataStore.size() > position)
{
item = mDataStore.remove(position);
if(mViewTypeMap.get(item.getViewType()) == position)
{
generateViewTypeMapping();
}
notifyItemRemoved(position);
}
return item;
}
/**
* Remove an item
* @param item
*/
public void removeItem(RecyclableViewItem item){
if(mDataStore != null && !mDataStore.isEmpty()){
int position = mDataStore.indexOf(item);
if(mDataStore.remove(item))
{
if(mViewTypeMap.get(item.getViewType()) == position)
{
generateViewTypeMapping();
}
notifyItemRemoved(position);
}
}
}
/**
* Set the given item at specified position
* @param position
* @param item
*/
public void setItemAtPosition(int position, RecyclableViewItem item){
if(mDataStore != null && !mDataStore.isEmpty())
{
int viewType = mDataStore.get(position).getViewType();
mDataStore.set(position, item);
if(mViewTypeMap.get(viewType) == position)
{
generateViewTypeMapping();
}
else {
addMappingForItem(item, position);
}
notifyItemChanged(position);
}
}
/**
*
* @param position
* @return item at {@param position}
*/
public RecyclableViewItem getItemAtPosition(int position)
{
if(mDataStore != null && !mDataStore.isEmpty() && position >=0 && position < mDataStore.size())
{
return mDataStore.get(position);
}
return null;
}
/**
*
* @param position
* @return Unique identifier for the item at {@param position}
*/
@Override
public long getItemId(int position) {
if(mDataStore != null && !mDataStore.isEmpty() && position >=0 && position < mDataStore.size())
{
RecyclableViewItem item = mDataStore.get(position);
if(item instanceof Identifiable)
{
return ((Identifiable) item).getId();
}
}
return super.getItemId(position);
}
/**
* Move an item from position {@param fromPos} to position {@param toPos}
* @param fromPos
* @param toPos
*/
public void moveItem(int fromPos, int toPos)
{
if(mDataStore != null && !mDataStore.isEmpty())
{
RecyclableViewItem item = mDataStore.remove(fromPos);
mDataStore.add(toPos, item);
if(mViewTypeMap.get(item.getViewType()) == fromPos)
{
mViewTypeMap.put(item.getViewType(), toPos);
}
notifyItemMoved(fromPos, toPos);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int position = mViewTypeMap.get(viewType);
if(position >= 0)
{
return mDataStore.get(position).onCreateViewHolder(parent, mItemClickListener);
}
return null;
}
protected int viewTypePosition(int viewType){
return mViewTypeMap.get(viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
mDataStore.get(position).onBindViewHolder(this, holder);
//TODO set the item click listener here
}
@Override
public int getItemCount() {
if(mDataStore != null)
{
return mDataStore.size();
}
return 0;
}
@Override
public int getItemViewType(int position) {
if(mDataStore != null && position < mDataStore.size())
{
return mDataStore.get(position).getViewType();
}
return super.getItemViewType(position);
}
/**
* interface to listen for item clicks
*/
public interface onItemClickListener{
void onItemClick(int position, View clickedView);
}
}
/**
* Created by Mehedi on 6/2/15.
*
* An item that is uniquely identifiable
*/
public interface Identifiable {
/**
*
* @return The unique ID of this item
*/
int getId();
}
/**
* Created by Mehedi on 5/31/15.
*
* An item that is Recyclable, can be shown in a RecyclerView
*/
public interface RecyclableViewItem<T extends RecyclerView.ViewHolder> {
/**
*
* @return Class of the ViewHolder
*/
Class<T> getViewHolderClassType();
/**
*
* @return Type of View
*/
int getViewType();
/**
*
* @param parent
* @param itemClickListener
* @return Create and return the ViewHolder
*/
T onCreateViewHolder(ViewGroup parent, GenericRecycleAdapter.onItemClickListener itemClickListener);
/**
* Update the View
* @param viewHolder
*/
void onBindViewHolder(RecyclerView.Adapter adapter, T viewHolder);
}
/**
* Created by Mehedi on 6/1/15.
*
* Pulled from AOSP source base and modified.
*
* Draws a divider in between RecyclerView items
*/
public class RecyclerViewDivider extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public RecyclerViewDivider(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment