学习一波自定义RecyclerView的ItemDecoration

ItemDecoration是recyclerView的静态内部类,主要是为RecyclerView的Item绘制各种特效,添加效果,最常用的就是绘制分割线
ItemDecoration只有三个常用方法,一个是getItemOffsets设置偏离值,一个ondraw绘制,还有一个ondrawOver主要是浮层绘制

 public abstract static class ItemDecoration {
        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn before the item views are drawn,
         * and will thus appear underneath the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView
         */
        public void onDraw(Canvas c, RecyclerView parent, State state) {
            onDraw(c, parent);
        }

        /**
         * @deprecated
         * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDraw(Canvas c, RecyclerView parent) {
        }

        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn after the item views are drawn
         * and will thus appear over the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView.
         */
        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
            onDrawOver(c, parent);
        }

        /**
         * @deprecated
         * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDrawOver(Canvas c, RecyclerView parent) {
        }


        /**
         * @deprecated
         * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
         */
        @Deprecated
        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
            outRect.set(0, 0, 0, 0);
        }

        /**
         * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
         * the number of pixels that the item view should be inset by, similar to padding or margin.
         * The default implementation sets the bounds of outRect to 0 and returns.
         *
         * <p>
         * If this ItemDecoration does not affect the positioning of item views, it should set
         * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
         * before returning.
         *
         * <p>
         * If you need to access Adapter for additional data, you can call
         * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
         * View.
         *
         * @param outRect Rect to receive the output.
         * @param view    The child view to decorate
         * @param parent  RecyclerView this ItemDecoration is decorating
         * @param state   The current state of RecyclerView.
         */
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                    parent);
        }
    }

getItemOffsets方法是在四个方向设置偏移值


       /**1. outRect:全为 0 的 Rect(包括着Item)
        * 2. view:RecyclerView 中的 视图Item
        * 3. parent:RecyclerView 本身
        * 4. state:状态
        * /
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
      // 4个参数分别对应左(Left)、上(Top)、右(Right)、下(Bottom)
      // 上述语句代表:左和下偏移长度=50px,右 和 上 偏移长度 = 0
      outRect.set(50, 0, 0,50);
  }

这里写图片描述

自定义recyclerView的itemDecoration只要需要继承这个类即可,其余部分就和绘制自定义控件的方式一样
1,自定义分割线
**这里写图片描述**

class LineItemDecoration : RecyclerView.ItemDecoration() {
    private val mPaint=Paint()
    // 设置矩形(分割线)的宽度为1px
    val mDivider = 1
    // 在构造函数里进行绘制的初始化,如画笔属性设置等
    init {
        mPaint.color = Color.GRAY
    }

    // 重写getItemOffsets()方法
    // 作用:设置矩形OutRect 与 Item 的间隔区域
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.set(0,0,0,1)
    }

    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State?) {
        super.onDraw(c, parent, state)

        // 获取RecyclerView的Child view的个数
        val childCount = parent.childCount

        // 遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
        for (i in 0 until childCount) {
            // 获取每个Item的位置
            val child = parent.getChildAt(i)
            val index = parent.getChildAdapterPosition(child)
            // 获取布局参数
            val params = child.layoutParams as RecyclerView.LayoutParams

            // 矩形左上顶点 = (ItemView的左边界,ItemView的下边界)
            // ItemView的左边界 = RecyclerView 的左边界 = paddingLeft距离 后的位置
            val left = parent.paddingLeft

            // ItemView的下边界:ItemView 的 bottom坐标 + 距离RecyclerView底部距离 +translationY
            val top = child.bottom + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child))

            // 矩形右下顶点 = (ItemView的右边界,矩形的下边界)
            // ItemView的右边界 = RecyclerView 的右边界减去 paddingRight 后的坐标位置
            val right = parent.width - parent.paddingRight
            // 绘制分割线的下边界 = ItemView的下边界+分割线的高度
            val bottom = top + mDivider

            // 通过Canvas绘制矩形(分割线)
            c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), mPaint)
        }
    }
}

2,自定义时间轴
这里写图片描述

class DividerItemDecoration(val timeData: ArrayList<String>)// 在构造函数里进行绘制的初始化,如画笔属性设置等
    : RecyclerView.ItemDecoration() {

    // 写右边字的画笔(具体信息)
    private val mPaint: Paint

    // 写左边日期字的画笔( 时间 )
    private val mPaint1: Paint

    // 左 上偏移长度
    private val itemView_leftinterval: Int


    // 图标
    private var mIcon: Bitmap? = null


    init {

        // 轴点画笔(红色)
        mPaint = Paint()
        mPaint.color = Color.BLUE

        // 左边时间文本画笔(蓝色)
        // 此处设置了两只分别设置 时分 & 年月
        mPaint1 = Paint()
        mPaint1.color = Color.BLUE
        mPaint1.textSize = 25f


        // 赋值ItemView的左偏移长度为200
        itemView_leftinterval = 200


        // 获取图标资源
        mIcon = BitmapFactory.decodeResource(BaseApplication.mContext.getResources(), R.drawable.car);

    }

    // 重写getItemOffsets()方法
    // 作用:设置ItemView 左 & 上偏移长度
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
        super.getItemOffsets(outRect, view, parent, state)
        // 设置ItemView的左 & 上偏移长度分别为200 px & 50px,即此为onDraw()可绘制的区域
        outRect.set(itemView_leftinterval, 0, 0, 0)

    }

    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State?) {
        super.onDraw(c, parent, state)

        val childCount = parent.childCount

        // 遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
        for (i in 0 until childCount) {

            // 获取每个Item对象
            val child = parent.getChildAt(i)
            Logger.e("position =" + i)
            /**
             * 绘制轴点
             */
            // 轴点 = 圆 = 圆心(x,y)
            val centerx = (child.left - itemView_leftinterval / 3).toFloat()
            val centery = (child.top + child.height / 2).toFloat()

            // 通过Canvas绘制角标
            val width = mIcon?.width;
            val height = mIcon?.height;
            c.drawBitmap(mIcon, centerx - width!! / 4, centery - height!! / 2, mPaint);

            val upLine_up_y = child.top.toFloat()

            // 下端点坐标(x,y)
            val upLine_bottom_y = centery

            //绘制上半部轴线
            c.drawLine(centerx, upLine_up_y, centerx, upLine_bottom_y - height / 3, mPaint)

            val bottom_up_y = centery + height / 3

            // 下端点坐标(x,y)
            val bottomLine_bottom_y = child.bottom.toFloat()

            //绘制下半部轴线
            c.drawLine(centerx, bottom_up_y, centerx, bottomLine_bottom_y, mPaint)

            // 获取每个Item的位置
            val index = parent.getChildAdapterPosition(child)
            // 设置文本起始坐标
            val Text_x = (child.left - itemView_leftinterval).toFloat()
            /**
             * 绘制左边时间文本
             */
            c.drawText(timeData.get(index), Text_x + itemView_leftinterval * 1f / 10, upLine_bottom_y - dp2px(BaseApplication.mContext, 10f), mPaint1)

        }
    }

}

猜你喜欢

转载自blog.csdn.net/villa_mou/article/details/79444857