RecycleView.ItemDecoration全面了解

本文深入解析RecyclerView.ItemDecoration类,介绍如何使用自定义ItemDecoration来快速实现RecycleView的视觉效果,包括分割线、时间轴等复杂UI设计。通过具体代码示例,详细解释getItemOffsets、onDraw和onDrawOver三个核心方法的作用及其实现技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在开发的时候,如果你用到的是RecycleView,就常常会有下划线的视觉。平时我们就直接在item视觉里就加上了上划线,但今天用了ItemDecoration类,会更快速地实现我们的表现效果。

使用

在自定义ItemDecoration通常要复写其3个方法

public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    // 方法1:getItemOffsets()
    // 作用:设置ItemView的内嵌偏移长度(inset)
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
       ...
  }
  
    // 方法2:onDraw()
    // 作用:在子视图上设置绘制范围,并绘制内容
    // 类似平时自定义View时写onDraw()一样
    // 绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
    ...
  }

    // 方法3:onDrawOver()
    // 作用:同样是绘制内容,但与onDraw()的区别是:绘制在图层的最上层
    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    .....
}

getItemOffsets()

在这里插入图片描述

像图片所看到RecycleView外面会包裹一层矩形,而outRect的与ItemVIeww的间隔则是由outRect 中的topleftrightbottom参数 控制

onDraw()

有两个注意的地方

  • ItemdecorationonDraw()绘制会先于ItemViewonDraw()绘制,
  • getItemOffsets() 针对是每一个ItemView的,而 onDraw() 针对 RecyclerView 本身
@Override
    public void onDraw(Canvas c, RecyclerView parent, 
                                  RecyclerView.State state) {

    // RecyclerView 的左边界加上 paddingLeft距离 后的坐标位置
    final int left = parent.getPaddingLeft();
    // RecyclerView 的右边界减去 paddingRight 后的坐标位置
    final int right = parent.getWidth() - parent.getPaddingRight();
    // 即左右边界就是 RecyclerView 的 ItemView区域

    // 获取RecyclerView的Child view的个数
    final int childCount = parent.getChildCount();

    // 设置布局参数
    final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                .getLayoutParams();

    // 遍历每个RecyclerView的Child view
    // 分别获取它们的位置信息,然后再绘制内容
    for (int i = 0; i < childCount; i++) {
        final View child = parent.getChildAt(i);
        int index = parent.getChildAdapterPosition(view);
            // 第一个Item不需要绘制
            if ( index == 0 ) {
                continue;
            }
        // ItemView的下边界:ItemView 的 bottom坐标 + 距离RecyclerView底部距离 +translationY
        final int top = child.getBottom() + params.bottomMargin +
                Math.round(ViewCompat.getTranslationY(child));
        // 绘制分割线的下边界 = ItemView的下边界+分割线的高度
        final int bottom = top + mDivider.getIntrinsicHeight();
        mDivider.setBounds(left, top, right, bottom);
        mDivider.draw(c);
    }

此处遍历的RecyclerView的ItemView(即Child view),并不是 Adapter 设置的每一个 item,而是可见的 item

onDrawOver()

Itemdecoration的onDrawOver()绘制 是后于 ItemView的onDraw()绘制

举个栗子

了解完ItemDecoration的基本知识后,开始写个时间轴效果
代码中主要的类DividerItemDecoration的实现

public class DividerItemDecoration extends RecyclerView.ItemDecoration{

    int item_top;
    int item_left;

    private Paint mPaint1;
    private Paint mPaint2;
    private Paint mPaint3;

    // 轴点半径
    private int circle_radius;

    public DividerItemDecoration() {
        mPaint1 = new Paint();
        mPaint2 = new Paint();
        mPaint3= new Paint();
        mPaint1.setStrokeWidth(4f);
        mPaint2.setStrokeWidth(4f);
        mPaint1.setColor(Color.RED);
        mPaint2.setColor(Color.BLUE);
        mPaint3.setColor(Color.BLUE);
        mPaint3.setTextSize(30);

        item_top = 50;
        item_left = 200;

        circle_radius = 12;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);

        int itemPosition = parent.getChildAdapterPosition(view);
        outRect.set(item_left, item_top, 0 ,0 );
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);

        //获取RecycleView的可见Child view 的个数
        int childCount = parent.getChildCount();

        //遍历每个item
        for (int i = 0; i < childCount; i++){
            View child = parent.getChildAt(i);
            int index = parent.getChildAdapterPosition(child);

            //圆心位置
            float circle_y = child.getTop() - item_top + (item_top + child.getHeight()) / 2;
            float circle_x = child.getLeft() - item_left/3;

			/**
			*这里除了圆形,可以定义自己想要实现的效果
			*绘制时间轴空心圆点
			*	mPaint.setStyle(Paint.Style.STROKE);
			*	c.drawCircle(centerX,centerY,mNodeRadius,mPaint);
			*	mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
			*/
            c.drawCircle(circle_x, circle_y, circle_radius, mPaint1);

            //上半轴
            float upLine_top_x = circle_x;
            float upLine_top_y = child.getTop() - item_top;

            float upLine_bottom_x = circle_x;
            float upLine_bottom_y = circle_y - circle_radius / 2;

			//第一个ItemView不需要在上面绘制竖线
            if (index != 0)
                c.drawLine(upLine_top_x, upLine_top_y, upLine_bottom_x, upLine_bottom_y, mPaint1);

            //下半轴
            float bottomLine_top_x = circle_x;
            float bottomLine_top_y = circle_y + circle_radius / 2;

            float bottomLine_bottom_x = circle_x;
            float bottomLine_bottom_y = child.getTop() + child.getHeight();

            if (index != childCount - 1)
                c.drawLine(bottomLine_top_x, bottomLine_top_y, bottomLine_bottom_x, bottomLine_bottom_y, mPaint2);


            //设置文本
            float text_x = child.getLeft() - item_left * 5/6;
            float text_y = upLine_bottom_y;

            c.drawText("哈哈哈", text_x, text_y, mPaint3);
            c.drawText("2017.4.03", text_x + 5, text_y + 20, mPaint2);
        }

    }

}

之后绑定在Recycleview就可以显示出效果了

// 绑定数据到RecyclerView
    public void initView(){
        Rv = (RecyclerView) findViewById(R.id.my_recycler_view);
        //使用线性布局
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        Rv.setLayoutManager(layoutManager);
        Rv.setHasFixedSize(true);

        //用自定义分割线类设置分割线
        Rv.addItemDecoration(new DividerItemDecoration());

        //为ListView绑定适配器
        myAdapter = new DividerAdapter(this,listItem);
        Rv.setAdapter(myAdapter);
    }

然后效果如下图:
时光轴效果

现在可以开心的去自己定义ItemDecoration

参考: 教你玩转 Android RecyclerView:深入解析 RecyclerView.ItemDecoration类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值