Created
March 27, 2017 09:08
-
-
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
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.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); | |
} | |
} |
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
/** | |
* 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(); | |
} |
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
/** | |
* 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); | |
} |
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
/** | |
* 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