一.概述
为了项目的需求,自定义了一个seekbar可当做时间轴,且是可以支持滑动的.效果图如下:
二.重写onMessure
这里只是简单的处理了以下AT_MOST的情况.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST) {// 相当于 wrap_content
widthSize = (int) (mStepRadius * 2 * mStepCount + getPaddingLeft() + getPaddingRight());
}
if (heightMode == MeasureSpec.AT_MOST) {
heightSize = (int) mStepRadius * 2 + getPaddingBottom()
+ getPaddingTop();
}
setMeasuredDimension(widthSize, heightSize);
}
三.绘制过程
1.首先绘制背景条,也就是最底层的颜色
/**
* 画背景条
*
* @param canvas
* 画布
*/
private void drawBarBg(Canvas canvas) {
canvas.save();
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(mBarColor);
RectF r = new RectF(getPaddingLeft() + mStepRadius, getPaddingTop()
+ mStepRadius - mBarHeight / 2, getMeasuredWidth()
- getPaddingRight() - mStepRadius, getPaddingTop()
+ mStepRadius + mBarHeight / 2);
canvas.drawRect(r, paint);
canvas.restore();
}
2.绘制进度条,滑动的颜色
/**
* 画进度
*
* @param canvas
* 画布
*/
private void drawProgress(Canvas canvas) {
canvas.save();
float barWidth = getMeasuredWidth() - mStepRadius * 2
- getPaddingLeft() - getPaddingRight();// 背景条的总宽度
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(mProgressColor);
RectF r = new RectF(getPaddingLeft() + mStepRadius, getPaddingTop()
+ mStepRadius - mBarHeight / 2, getPaddingLeft() + mStepRadius
+ barWidth * (mProgress), getPaddingTop() + mStepRadius
+ mBarHeight / 2);
canvas.drawRect(r, paint);
canvas.restore();
}
3.绘制所有初始的节点
/**
* 画节点
*
* @param canvas
* 画布
*/
private void drawSteps(Canvas canvas) {
canvas.save();
float barWidth = getMeasuredWidth() - mStepRadius * 2
- getPaddingLeft() - getPaddingRight();// 背景条的总宽度
for (int i = 0; i < mStepCount; i++) {
int pivotX = (int) (mStepRadius + getPaddingLeft() + i * barWidth
/ (mStepCount - 1));// 当前节点圆的中心点X坐标
// 下面开始画圆
mPaint.setColor(mStepNormalColor);
RectF oval = new RectF(pivotX - mStepRadius, getPaddingTop(),
pivotX + mStepRadius, getPaddingTop() + mStepRadius * 2);
canvas.drawOval(oval, mPaint);
}
canvas.restore();
}
4.绘制当前滑动过的节点
/**
* 画当前移动的图标
* @param canvas
*/
private void drawCurrentStep(Canvas canvas) {
canvas.save();
float barWidth = getMeasuredWidth() - mStepRadius * 2
- getPaddingLeft() - getPaddingRight();// 背景条的总宽度
float pivotX=mStepRadius + barWidth * mProgress;
mPaint.setColor(mStepSelectedColor);
//这个圆可以换成自己需要的图片
RectF oval = new RectF(pivotX - mStepRadius, getPaddingTop(),
pivotX + mStepRadius, getPaddingTop() + mStepRadius * 2);
canvas.drawOval(oval, mPaint);
canvas.restore();
}
四.滑动处理,重写了onToucheEvent方法
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mCanDrag) {// 支持拖动
float x = event.getX();
//防止快速滑动出屏幕时候 不执行up的逻辑
if (event.getAction() != MotionEvent.ACTION_UP) {
if (x < getPaddingLeft() + mStepRadius
|| x > getMeasuredWidth() - getPaddingRight() - mStepRadius) {
return true;
}
}
x = x - getPaddingLeft() - mStepRadius;
float barWidth = getMeasuredWidth() - mStepRadius * 2
- getPaddingLeft() - getPaddingRight();// 背景条的总宽度
mProgress = x / barWidth;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
System.out.println("up");
// 判断离哪个节点更近
int temp = mCurrentStep;
float minDiatance = Math.abs(mProgress);
for (int i = 0; i < mStepCount; i++) {
if (minDiatance >= (Math.abs(mProgress - i
/ (float) (mStepCount - 1)))) {
minDiatance = Math.abs(mProgress - i
/ (float) (mStepCount - 1));
temp = i;
}
}
// 如果目前的离得最近的节点与旧的节点步数不一致,通知监听器
if (temp != mCurrentStep) {
mCurrentStep = temp;
if (mStepChangedListener != null) {
mStepChangedListener.onStepChanged(mCurrentStep);
}
}
mProgress = mCurrentStep / (float) (mStepCount - 1);
break;
}
invalidate();
return true;
} else {// 不支持拖动
return false;
}
}
五.总结
上面简单的分析了以下这个自定义的过程,想看源码的移步github