常规形状的滑动指示控件样式一般只需要通过Shape去配置样式就行,但如果UI设计需要的是自定义形状的控件就需要自定绘制实现,这边给出Android自定义菱形横向滑动指示器控件实现。
一、指示器控件自定义绘制实现
实现抽象效果大概如下:
--------------
/----/-------/
实现代码不多,直接贴结果,自己在style.xml样式文件里面定义下ScrollIndicator参数,滚动条背景色color_scroll_indicator_bg 和前景色 color_scroll_indicator_progress 也自己在样式文件里面自定义配置下就行。indicator_progress_width 为你自己需要配置的进度条宽度,不配置的话默认progress宽度为总宽度的三分一。
/**
* 滚动指示条
*/
public class ScrollIndicatorView extends View {
private int mBackgroundColor = Color.BLACK;
private int mProgressColor = Color.YELLOW;
private int mProgressWidth = 0;
private int mProgressRemainWidth = 0;
private Paint mPaint = null;
private Path mBackgroundPath = null;
private Path mProgressPath = null;
private float mScrollOffset = 0;
private float mAreaOffsetX = 0;
public ScrollIndicatorView(@NonNull Context context) {
this(context, null);
}
public ScrollIndicatorView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public ScrollIndicatorView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, -1);
}
public ScrollIndicatorView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
// 这边在样式配置文件里面自己配置下ScrollIndicator
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ScrollIndicator, defStyleAttr, defStyleRes);
mBackgroundColor = a.getColor(R.styleable.ScrollIndicator_indicator_background, getResources().getColor(R.color.color_scroll_indicator_bg, context.getTheme()));
mProgressColor = a.getColor(R.styleable.ScrollIndicator_indicator_progress, getResources().getColor(R.color.color_scroll_indicator_progress, context.getTheme()));
mProgressWidth = a.getDimensionPixelSize(R.styleable.ScrollIndicator_indicator_progress_width, 0);
a.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mBackgroundPath = new Path();
mProgressPath = new Path();
}
private void initPath() {
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
// 梯形X轴偏移量
mAreaOffsetX = (float) (viewHeight / Math.sqrt(3));
mBackgroundPath.moveTo(0, viewHeight);
mBackgroundPath.lineTo(mAreaOffsetX, 0);
mBackgroundPath.lineTo(viewWidth, 0);
mBackgroundPath.lineTo(viewWidth - mAreaOffsetX, viewHeight);
mBackgroundPath.close();
// 设置绘制为填充效果
mBackgroundPath.setFillType(Path.FillType.WINDING);
mProgressPath.setFillType(Path.FillType.WINDING);
if (mProgressWidth == 0) {// 默认progress宽度为总宽度的30%
mProgressWidth = viewWidth * 3 / 10;
}
mProgressRemainWidth = viewWidth - mProgressWidth;
}
/**
* 滚动滑出部分在剩余范围的比例,百分比参数单位
*
* @param offset
*/
public void updateProgress(float offset) {
mScrollOffset = offset;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
initPath();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制背景
mPaint.setColor(mBackgroundColor);
canvas.drawPath(mBackgroundPath, mPaint);
// 刷新绘制滚动条区域
mPaint.setColor(mProgressColor);
float maxRight = mProgressRemainWidth * mScrollOffset + mProgressWidth + mAreaOffsetX;
float maxLeft = mProgressRemainWidth * mScrollOffset + mAreaOffsetX;
// 校验滑动最大值,不超过控件宽度
if(maxRight > getMeasuredWidth()) {
maxRight = getMeasuredWidth();
maxLeft = maxRight - mProgressWidth;
}
// 路线要先重置再重新配置参数
mProgressPath.reset();
mProgressPath.moveTo(maxLeft - mAreaOffsetX, getMeasuredHeight());
mProgressPath.lineTo(maxLeft, 0);
mProgressPath.lineTo(maxRight , 0);
mProgressPath.lineTo(maxRight - mAreaOffsetX, getMeasuredHeight());
mProgressPath.close();
canvas.drawPath(mProgressPath, mPaint);
}
}
二、滚动控件使用
在Fragment或Activity中设置RecyclerView的滑动监听:
mRecyclerView.addOnScrollListener(mScrollListener);
滚动监听类实现:
private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int range=0;
int temp = mRecyclerView.computeHorizontalScrollRange();
if (temp > range) {
range = temp;
}
//滑块的偏移量
int offset = mRecyclerView.computeHorizontalScrollOffset();
//可视区域长度
int extent = mRecyclerView.computeHorizontalScrollExtent();
//滑出部分在剩余范围的比例
float proportion = (float) (offset * 1.0 / (range - extent));
// mIndicator为布局中的ScrollIndicatorView引用
mIndicator.updateProgress(proportion);
}
};
到这就完成了,可以自己修改ScrollIndicatorView中Path路径参数,去实现自己需要的形状。
三、其他实现参考
如果不需要自定义形状的滑动指示,可以参考 Android仿天猫横向滑动指示器功能的实现
扩展阅读:
- Android 弧形 RecyclerView 实现(Kotlin)
- 美图手机音乐Widget动画实现
- Android 心率动画自定义控件实现
- Android 卡片旋转切换动效实现详解
- Android 残影数字动画实现详解
微信公众号
转载请注明出处:陈文管的博客 – Android 自定义菱形横向滑动指示器控件