美文网首页
RecyclerView基础篇-ItemDecoration

RecyclerView基础篇-ItemDecoration

作者: dashingqi | 来源:发表于2020-08-31 16:37 被阅读0次
Android_Banner.jpg

简介

  • Decoration在英文中的意思是装饰,在RecyclerView中ItemDecoration就是每一个Item的装饰器。
  • 在上古时期,ListView很是流行,当时我们如果想要设置一个分隔线,我们仅仅在xml中指定 android:divider="1dp",就可以了,但是RecyclerView中没有提供相应的属性设置。
  • 如果想要实现分割线的效果,我们可以借助于ItemDecoration。

使用

实现分割线效果
  • 效果如下


    rv_decoration.gif
实现过程
  • 接上篇文章的代码做如下修改 :上篇文章
  • 修改activity_main.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   //新增了一个背景色
    android:background="#f4f4f4"
    tools:context=".GridLayoutManagerActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • 修改item.xml文件的bg
  <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    // 新增背景色
    android:background="#ffffff"
    android:padding="16dp">

    <ImageView
        android:id="@+id/ivCover"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="4dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:textColor="#333333"
        android:textSize="18sp"
        app:layout_constraintLeft_toRightOf="@+id/ivCover"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@+id/ivCover" />


    <TextView
        android:id="@+id/tvDesc"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="8dp"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="@+id/ivCover"
        app:layout_constraintLeft_toRightOf="@+id/ivCover"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvName"
        tools:text="测试测试测试测试" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • 新增ComItemDecoration文件
  class ComItemDecorate : RecyclerView.ItemDecoration() {

    /**
     * view:指代着每一个Item
     * outRect 是一个为0的Rect,填充在Item的四周
     */
    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        // 让item的rect的底部 高度设置为16f
        outRect.bottom = DensityUtils.dip2pxInt(parent.context, 16f)

    }

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

    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
    }
}
  • 为RecyclerView设置ItemDecoration
    var adapter = GridLayoutAdapter(items)
        rv.addItemDecoration(ComItemDecorate())
        rv.adapter = adapter
总结
  • 在上述代码中,我们让ItemView四周的rect的底部高度设置为2,这样就露出了背景色,形成了分割线,
  • 这样的分隔线的线程取决于RecyclerView的背景色。
  • 对此,在RecyclerView.ItemDecoration中为我们提供了onDraw()方法,可通过该方法画出一个分割线
ItemDecoration.onDraw()
  • onDraw()方法是具有绘制的能力
  • 该方法是和getItemOffsets()配合使用的,getItemOffsets()是把ItemView的四周撑开,而我们的onDraw()方法,通过计算每个Item所处的坐标点,来绘制图形,从而形成我们想要的效果
  • 我们要在每个Item的底部画一个高度16的红色矩形,填充在每一个Item的底部
  • 代码如下--- 使用ItemDecoration()中的onDraw()方法
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDraw(c, parent, state)
        // item数
        val childItemCount = parent.childCount

        for (index in 0..childItemCount-1) {
            val itemView = parent.getChildAt(index)
            val top = itemView.top
            val left = parent.paddingLeft
            val right = parent.paddingRight
            val bottom = itemView.top + DensityUtils.dip2pxInt(parent.context, 16f)
            val rect = Rect(top, left, right, bottom)
            c.drawRect(rect, drawPaint)
        }
    }
  • 效果如下


    rv_draw.gif
getItemOffset()配合onDraw()方法实现时间轴
  • 效果图如下


    rv_timeline.gif
  • 实现代码如下
class TimelineItemDecoration : RecyclerView.ItemDecoration() {

    private val paint: Paint = Paint()

    private val offset = 120

    init {
        //设置画笔
        paint.isAntiAlias = true
        paint.style = Paint.Style.FILL_AND_STROKE
        paint.color = Color.RED
    }


    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {

        val position = parent.getChildAdapterPosition(view)
        //当是第一条数据的时候,不设置outRect的顶部
        val topOffset = offset
        if (position != 0) {
            outRect.top = topOffset
        }

        outRect.left = offset
    }

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

        // 条目个数
        val childItemCount = parent.childCount
        for (position in 0 until childItemCount) {
            // 对应的ItemView
            val itemView = parent.getChildAt(position)

            val index = parent.getChildAdapterPosition(itemView)

            // 第一个条目 没有做outRect的top拉伸
            var dividerTop = itemView.top - offset
            if (index == 0) {
                dividerTop = itemView.top
            }

            val dividerBottom = itemView.bottom

            val dividerLeft = parent.paddingLeft

            val dividerRight = parent.width - parent.paddingRight
            //画中心圆

            val radiusX = dividerLeft + offset / 2

            val radiusY = (dividerBottom - dividerTop) / 2 + dividerTop

            c.drawCircle(radiusX.toFloat(), radiusY.toFloat(), radiusX / 2f, paint)

            // 画第一条直线

            val oneLineStartX = dividerLeft + radiusX

            val oneLineStartY = dividerTop

            val oneLineEndX = dividerLeft + radiusX

            val oneLineEndY = dividerTop + (dividerBottom - dividerTop) / 2 - radiusX / 2

            c.drawLine(
                oneLineStartX.toFloat(), oneLineStartY.toFloat(),
                oneLineEndX.toFloat(), oneLineEndY.toFloat(), paint
            )

            // 画第二条直线

            val twoLineStartX = dividerLeft + radiusX
            val twoLineStartY = (dividerBottom - dividerTop) / 2  + dividerTop
            val twoLineEndX = dividerLeft + radiusX
            val twoLineEndY = dividerBottom

            c.drawLine(
                twoLineStartX.toFloat(),
                twoLineStartY.toFloat(), twoLineEndX.toFloat(), twoLineEndY.toFloat(), paint
            )
        }

    }
}
onDrawOver()
  • 此方法的用处就是将绘制的内容绘制在ItemView之上
  • 相比较于 onDraw(),onDraw()是将内容绘制在ItemView之下的。

相关文章

网友评论

      本文标题:RecyclerView基础篇-ItemDecoration

      本文链接:https://www.haomeiwen.com/subject/mrfusktx.html