使用RecyclerView.ItemDecoration自定义RecyclerView圆角滚动条
使用RecyclerView.ItemDecoration自定义RecyclerView圆角滚动条
其实RecyclerView自带滚动条,设置android:scrollbars="vertical"即可。想让其长期显示,设置android:fadeScrollbars="false"即可。但是滚动条的端点样式是矩形的,有时会不符合设计要求,这时可以自定义一个滚动条来实现设计要求。
依据
主要想法是利用当前页第一条可视条目的位置计算滚动条的位置,再由当前页可视条目数量与总列表数量的比例计算滚动条在RecyclerView内的高度。
步骤一
继承类RecyclerView.ItemDecoration并实现方法onDrawOver方法
步骤二:在onDrawOver方法内实现以下逻辑
- 取得第一条条目的位置
- 均分容器高度
- 根据当前页显示的数量,得出滚动条要显示的高度
- 绘制直线(滚动条)
代码如下:
package com.hanvon;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class Decoration extends RecyclerView.ItemDecoration {
//抗锯齿 : Paint.ANTI_ALIAS_FLAG
//闪烁时启动抖动 : Paint.DITHER_FLAG
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
private float strokeWidth = 2;
private float scrollbarMargin = 0;
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int childCount = parent.getChildCount();
int itemCount = state.getItemCount();
if (childCount == 0) return;
Log.i("LayoutManager", "childCount: " + childCount + " itemCount=" + itemCount);
paint.setStrokeWidth(1);
paint.setColor(Color.RED);
//绘制滚动条
if (childCount == itemCount) return;//如果不超过两页,不用绘制滚动条
//获取当前Page第一个条目的位置
View childAt = parent.getChildAt(0);
int position = parent.getChildLayoutPosition(childAt);
//均分RecyclerView的高度,计算单条目录所占比重
float itemHeight = (parent.getHeight() - strokeWidth) / itemCount;
float half = strokeWidth / 2;
int viewWidth = parent.getWidth();
float x = viewWidth - scrollbarMargin - 1;//- half;//靠右绘制并显示右边距,所以要减掉边距和至少1线宽(当StrokeWidth=1时也能显示)
paint.setStrokeWidth(strokeWidth);//线宽
paint.setStrokeCap(Paint.Cap.ROUND);//圆角
c.drawLine(x, position * itemHeight + half, x, (position + childCount) * itemHeight + half, paint);
//测试辅助线
/*paint.setTextSize(8f);
paint.setStrokeWidth(1);
c.drawLine(x - 4, 0, x - 4, parent.getHeight(), paint);
for (int i1 = 0; i1 < itemCount + 2; i1++) {
c.drawLine(0, i1 * itemHeight + half, viewWidth, i1 * itemHeight + half, paint);
c.drawText("" + i1, viewWidth - 50, i1 * itemHeight - 8, paint);
}*/
}
}
要注意代码里面的float itemHeight = (parent.getHeight() - strokeWidth) / itemCount;计算减去了strokeWidth。
原因是线端点样式设置成了paint.setStrokeCap(Paint.Cap.ROUND),所以预留了端点样式的绘制位置,如果预留的话,在边沿的位置端点会被截断而不显示。
步骤三,在RecyclerView上使用该ItemDecoration
rvList.addItemDecoration(new Decoration());
不足
- 不能拖动滚动条
- 因为是按条目个数算显示滚动条高度,当条目显示一半时,滚动条占比可能不精确,不过只是单纯显示,应该够用了

浙公网安备 33010602011771号