ItemDecoration based on viewtype in recyclerview

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));

Here's a shorter code to draw divider for certain view type only that can be easily included in your activity/fragment class:

recyclerView.addItemDecoration(new DividerItemDecoration(this, linearLayoutManager.getOrientation()) {
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            Drawable d = getDrawable();
            for (int i = 0; i < parent.getChildCount(); i++) {
                View view = parent.getChildAt(i);
                int position = parent.getChildAdapterPosition(view);
                int viewType = parent.getAdapter().getItemViewType(position);
                
                // Draw divider only for view type 2 (can also put position here to remove for certain positions)
                if(viewType == 2) {
                    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
                    int top = view.getBottom() + params.bottomMargin;
                    int bottom = top + d.getIntrinsicHeight();
                    d.setBounds(0, top, parent.getRight(), bottom);
                    d.draw(c);
                }
            }
        }
    });