I have multiple view types in my RecyclerView
and I want to add an ItemDecoration
based on the views type. Is there a way to do this?
This will add a decoration to every element:
recyclerView.addItemDecoration(decoration);
I saw this library but it supports only LinearLayoutManager
vertical or horizontal, but I am using GrildLayoutManager
and I use drawables for dividers.
An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapter's data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.
Yes, you can.
If you draw the decoration yourself, you can distinguish between different view types in getItemOffsets
and onDraw
by accessing the same method on the adapter like this:
// get the position
int position = parent.getChildAdapterPosition(view);
// get the view type
int viewType = parent.getAdapter().getItemViewType(position);
Using this, you can draw your decoration only for your selected views. By accessing getLeft()
and getRight()
that code supports GridLayout
as well as LinearLayout
, to support horizontal alignment, the drawing just has to be done on the right side using the same approach.
In the end, you would create a decoration like the following:
public class DividerDecoration extends RecyclerView.ItemDecoration {
private final Paint mPaint;
private int mHeightDp;
public DividerDecoration(Context context) {
this(context, Color.argb((int) (255 * 0.2), 0, 0, 0), 1f);
}
public DividerDecoration(Context context, int color, float heightDp) {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(color);
mHeightDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightDp, context.getResources().getDisplayMetrics());
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == MY_VIEW_TYPE) {
outRect.set(0, 0, 0, mHeightDp);
} else {
outRect.setEmpty();
}
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == MY_VIEW_TYPE) {
c.drawRect(view.getLeft(), view.getBottom(), view.getRight(), view.getBottom() + mHeightDp, mPaint);
}
}
}
}
There is a similar sample on GitHub with a demo project, which will not draw before or after header views or at the very end.
Based on @David MedenJak answer, I had made my own Item Decorator for different view types as the answer lag in one condition as it draws decorator above section, if it comes after any normal row,
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import java.util.Locale;
import mp.data.modal.MRecyclerListItem;
public class HeaderSimpleDividerDecoration extends RecyclerView.ItemDecoration {
private int dividerHeight;
private Paint dividerPaint;
public HeaderSimpleDividerDecoration(Context context, @DimenRes int divider_height, @ColorRes int color) {
dividerPaint = new Paint();
dividerPaint.setColor(getColor(context, color));
dividerHeight = context.getResources().getDimensionPixelSize(divider_height);
}
private int getColor(Context context, @ColorRes int drawable) {
return ContextCompat.getColor(context, drawable);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int position = parent.getChildAdapterPosition(view);
if(-1 >= position)
return;
int viewType = parent.getAdapter().getItemViewType(position);
if (MRecyclerListItem.TYPE_NORMAL == viewType) {
// outRect.set(0, 0, 0, mHeightDp);
outRect.bottom = dividerHeight;
} else
outRect.setEmpty();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int childCount = parent.getChildCount() -1;
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int top = parent.getPaddingTop();
int bottom = parent.getHeight() - parent.getPaddingBottom();
int itemCount = parent.getAdapter().getItemCount();
for (int i = 0; i < childCount ; i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
int viewType = parent.getAdapter().getItemViewType(position);
if (MRecyclerListItem.TYPE_NORMAL == viewType) {
int nextItem = position + 1;
if(nextItem < itemCount)
{
int nextViewType = parent.getAdapter().getItemViewType(nextItem);
if(MRecyclerListItem.TYPE_NORMAL != nextViewType)
continue;
}
float topDraw = view.getBottom();
float bottomDraw = view.getBottom() + dividerHeight;
c.drawRect(left, topDraw, right, bottomDraw, dividerPaint);
}
}
}
}
MRecyclerListItem.TYPE_NORMAL is your view type of normal row(other than header) call the above in following manager,
mRecyclerview.addItemDecoration(new HeaderSimpleDividerDecoration(context,
2dp , R.color.view_profile_edit_view));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With