RecyclerView ItemDecoration 自定义高度和颜色

Posted 威威dett

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RecyclerView ItemDecoration 自定义高度和颜色相关的知识,希望对你有一定的参考价值。

自定义高度和颜色RecyclerView ItemDecoration

自定义RecyclerView ItemDecoration,针对RecyclerView的横向和竖向的分割线,具体特点如下

  1. 支持像ListView一样可以使用颜色作为分隔线(也支持drawable)
  2. 支持自定义分割线的高度
  3. 支持控制是否显示最后一条分割线

下面贴上完整代码供参考

/**
 * recycler view 横竖方向使用的divider
 *
 * @author wangjian
 */
public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration 

    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;
    private static final String TAG = "DividerItem";
    private static final int[] ATTRS = new int[]android.R.attr.listDivider;
    private Context mContext;
    private Drawable mDivider;
    private int mOrientation;
    private int mDividerHeight;
    private final Rect mBounds = new Rect();

    private boolean showLastDivider;

    public LinearDividerItemDecoration(Context context, int orientation) 
        this.mContext = context;
        TypedArray a = context.obtainStyledAttributes(ATTRS);
        this.mDivider = a.getDrawable(0);
        if (this.mDivider == null) 
            Log.w("DividerItem", "@android:attr/listDivider was not set in the theme used for this LinearDividerItemDecoration. Please set that attribute all call setDrawable()");
        

        a.recycle();
        this.setOrientation(orientation);
    

    /**
     * 设置divider方向
     *
     * @param orientation 方向
     */
    public void setOrientation(int orientation) 
        if (orientation != HORIZONTAL && orientation != VERTICAL) 
            throw new IllegalArgumentException("Invalid orientation. It should be either HORIZONTAL or VERTICAL");
         else 
            this.mOrientation = orientation;
        
    

    /**
     * 是否显示最后一条分割线
     */
    public void setShowLastDivider(boolean showLastDivider) 
        this.showLastDivider = showLastDivider;
    

    /**
     * 设置分割线drawable
     *
     * @param drawable drawable
     */
    public void setDrawable(@NonNull Drawable drawable) 
        this.mDivider = drawable;
        this.mDividerHeight = mDivider.getIntrinsicHeight();
    

    /**
     * 设置分割线drawable
     *
     * @param dividerColor 分割线颜色
     * @param dividerHeight 分割线高度,单位dp
     */
    public void setDrawable(@ColorInt int dividerColor, int dividerHeight) 
        this.mDivider = new ColorDrawable(dividerColor);
        this.mDividerHeight = DisplayUtils.dip2px(mContext, dividerHeight);
    

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) 
        if (parent.getLayoutManager() != null && this.mDivider != null) 
            if (this.mOrientation == VERTICAL) 
                this.drawVertical(c, parent);
             else 
                this.drawHorizontal(c, parent);
            
        
    

    private void drawVertical(Canvas canvas, RecyclerView parent) 
        canvas.save();
        int left;
        int right;
        if (parent.getClipToPadding()) 
            left = parent.getPaddingLeft();
            right = parent.getWidth() - parent.getPaddingRight();
            canvas.clipRect(left, parent.getPaddingTop(), right, parent.getHeight() - parent.getPaddingBottom());
         else 
            left = 0;
            right = parent.getWidth();
        

        int childCount = parent.getChildCount();
        childCount = showLastDivider ? childCount : childCount - 1;

        for (int i = 0; i < childCount; ++i) 
            View child = parent.getChildAt(i);
            parent.getDecoratedBoundsWithMargins(child, this.mBounds);
            int bottom = this.mBounds.bottom + Math.round(child.getTranslationY());
            int top = bottom - this.mDividerHeight;
            this.mDivider.setBounds(left, top, right, bottom);
            this.mDivider.draw(canvas);
        

        canvas.restore();
    

    private void drawHorizontal(Canvas canvas, RecyclerView parent) 
        canvas.save();
        int top;
        int bottom;
        if (parent.getClipToPadding()) 
            top = parent.getPaddingTop();
            bottom = parent.getHeight() - parent.getPaddingBottom();
            canvas.clipRect(parent.getPaddingLeft(), top, parent.getWidth() - parent.getPaddingRight(), bottom);
         else 
            top = 0;
            bottom = parent.getHeight();
        

        int childCount = parent.getChildCount();
        childCount = showLastDivider ? childCount : childCount - 1;

        for (int i = 0; i < childCount; ++i) 
            View child = parent.getChildAt(i);
            parent.getLayoutManager().getDecoratedBoundsWithMargins(child, this.mBounds);
            int right = this.mBounds.right + Math.round(child.getTranslationX());
            int left = right - this.mDividerHeight;
            this.mDivider.setBounds(left, top, right, bottom);
            this.mDivider.draw(canvas);
        

        canvas.restore();
    

    //由于Divider也有宽高,每一个Item需要向下或者向右偏移,给divider留出绘制空间
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) 
        if (mDivider == null) 
            outRect.set(0, 0, 0, 0);
            return;
        
        if (mOrientation == VERTICAL) 
            //parent.getChildCount() 不能拿到item的总数
            //https://stackoverflow.com/questions/29666598/android-recyclerview-finding-out-first
            // -and-last-view-on-itemdecoration
            int lastPosition = state.getItemCount() - 1;
            int position = parent.getChildAdapterPosition(view);
            if (position == lastPosition) 
                if (showLastDivider) 
                    // item view 距离下面的view间距是divider的高度
                    outRect.set(0, 0, 0, mDividerHeight);
                 else 
                    outRect.set(0, 0, 0, 0);
                
             else 
                outRect.set(0, 0, 0, mDividerHeight);
            
         else 
            int lastPosition = state.getItemCount() - 1;
            int position = parent.getChildAdapterPosition(view);
            if (showLastDivider || position < lastPosition) 
                outRect.set(0, 0, mDividerHeight, 0);
             else 
                outRect.set(0, 0, 0, 0);
            
        
    

工具类中的转换方法

    public static int dip2px(Context context, float dipValue) 
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        final float scale = displayMetrics.density;
        return (int) (dipValue * scale + 0.5f);
    

使用方法介绍,下面是在fragment中使用参考,具体的使用需要根据自己的界面做相应修改

RecyclerView recyclerView;
// 实例化分割线
LinearDividerItemDecoration divider = new LinearDividerItemDecoration(getActivity(),  LinearLayoutManager.VERTICAL);
// 设置分割线的颜色和高度,横向的时候使用方法一样
divider.setDrawable(getResources().getColor(R.color.list_divider), 1);

// 也支持定义的drawable和图片drawable
// divider.setDrawable(AppUtils.getDrawable(getActivity(), R.drawable.recycler_divider_10_dp));

// 添加分割线
recyclerView.addItemDecoration(divider);

下面分享上面自定义的drawable分割线,在drawable目录下创建drawable,recycler_divider_10_dp

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <gradient
        android:centerColor="#ff00ff00"
        android:endColor="#ff0000ff"
        android:startColor="#ffff0000"
        android:type="linear" />
    <size
        android:width="3dp"
        android:height="3dp" />

</shape>

以上是关于RecyclerView ItemDecoration 自定义高度和颜色的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView详解

RecyclerView

RecyclerView嵌套RecyclerView问题

RecyclerView小结

RecyclerView系列:RecyclerView嵌套RecyclerView(BaseRecyclerViewAdapterHelper实现)

recyclerview怎么监听滑动事件