效果:
分段式的进度条,支持单点、滑动更改进度,每一小段为一个整体,实际应用可以当做各种多档位调节开关使用。感觉该控件比较实用,便记录一下。
源码参考,修改了自己想要的样式,原博客样式圆角的https://blog.csdn.net/rexuezhonghun/article/details/126160548?spm=1001.2014.3001.5506
代码如下:
public class DragStepBar extends View {
//背景颜色
private int bgColor = Color.argb(255, 80, 80, 80);
//渐变颜色
private int gradientStart = Color.WHITE;
private int gradientEnd = Color.WHITE;
//遮罩颜色
private int dividerColor = Color.BLACK;
//画笔
private Paint paint;
//高度
private int barHeight;
//宽度
private int barWidth;
//步阶(开关的总档位数)
private int step = 6;
//当前步阶
private int curStep = 0;
//一段的宽度
private float stepWidth;
//分割线的宽度
private float dividerWidth;
//是否可以滑动
private boolean touchEnable = true;
private OnDragStepListener onDragStepListener;
public DragStepBar(Context context) {
this(context, null);
}
public DragStepBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DragStepBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
DisplayMetrics displayMetrics = getDisplayMetrics();
barWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 322, displayMetrics);
barHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 28, displayMetrics);
dividerWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, displayMetrics);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DragStepBar);
//获取进度条背景色
bgColor = a.getColor(R.styleable.DragStepBar_bar_bg, bgColor);
//获取渐变色开始颜色
gradientStart = a.getColor(R.styleable.DragStepBar_bar_color_start, gradientStart);
//获取渐变色结束颜色
gradientEnd = a.getColor(R.styleable.DragStepBar_bar_color_end, gradientEnd);
//分割线颜色
dividerColor = a.getColor(R.styleable.DragStepBar_bar_divider_color, dividerColor);
//分割线宽度
dividerWidth = a.getDimension(R.styleable.DragStepBar_bar_divider_width, dividerWidth);
//总步数
step = a.getInt(R.styleable.DragStepBar_bar_step_count, step);
//当前步数
curStep = a.getInt(R.styleable.DragStepBar_bar_cur_step, curStep);
if (curStep > step)
curStep = step;
a.recycle();
paint = new Paint();
}
private DisplayMetrics getDisplayMetrics() {
return getResources().getDisplayMetrics();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制底部背景
drawBackGround(canvas);
//绘制步阶进度
drawGradient(canvas);
//绘制分割线
drawShade(canvas);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {//宽高都是wrap_content,使用默认值
setBarMeasure(barWidth, barHeight);
} else if (widthMode == MeasureSpec.AT_MOST) {
setBarMeasure(barWidth, heightSize);
} else if (heightMode == MeasureSpec.AT_MOST) {
setBarMeasure(widthSize, barHeight);
} else {
setBarMeasure(widthSize, heightSize);
}
}
/**
* 根据测量的宽高计算出单个进度的宽度和圆角的大小
*/
private void setBarMeasure(int width, int height) {
barWidth = width;
barHeight = height;
stepWidth = (barWidth - (step - 1) * dividerWidth) / step;
setMeasuredDimension(width, height);
}
//绘制底色
private void drawBackGround(Canvas canvas) {
paint.reset();
paint.setAntiAlias(true);//抗锯齿
paint.setDither(true);//图形抖动
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(5);
paint.setColor(bgColor);
RectF rectF = new RectF(0, 0, barWidth, barHeight);
canvas.drawRect(rectF, paint);
}
//绘制渐变色
private void drawGradient(Canvas canvas) {
if (curStep == 0) return;
LinearGradient linearGradient = new LinearGradient(0, 0, barWidth, barHeight,
gradientStart, gradientEnd, Shader.TileMode.MIRROR);
// 设置画笔属性
paint.setAntiAlias(true); // 抗锯齿
paint.setDither(true); // 图形抖动
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(1);
paint.setShader(linearGradient);
// 绘制已完成进度的矩形
float completedWidth = curStep * stepWidth + (curStep - 1) * dividerWidth;
RectF completedRectF = new RectF(0, 0, completedWidth, barHeight);
canvas.drawRect(completedRectF, paint);
// 绘制未完成进度的矩形(可选,如果你想要显示未完成的部分)
float remainingWidth = barWidth - completedWidth;
if (remainingWidth > 0) {
RectF remainingRectF = new RectF(completedWidth, 0, barWidth, barHeight);
paint.setShader(null); // 移除渐变效果,可以使用纯色或其他效果
canvas.drawRect(remainingRectF, paint);
}
}
//绘制分割线
private void drawShade(Canvas canvas) {
paint.reset();
paint.setColor(dividerColor);
paint.setAntiAlias(true);//抗锯齿
paint.setDither(true);//图形抖动
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(1);
for (int i = 1; i < step; i++) {
float left = stepWidth * i + dividerWidth * (i - 1);
RectF rectF = new RectF(left, 0, left + dividerWidth, barHeight);
canvas.drawRect(rectF, paint);
}
}
//设置是否可点击
public void setTouchEnable(boolean touchEnable) {
this.touchEnable = touchEnable;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!touchEnable) {
return false;
}
//获取触摸坐标
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
updateStep(event.getX());
if (onDragStepListener != null)
onDragStepListener.onDragStep(curStep, false);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
updateStep(event.getX());
if (onDragStepListener != null)
onDragStepListener.onDragStep(curStep, true);
break;
}
getParent().requestDisallowInterceptTouchEvent(true);
return true;
}
private void updateStep(float x) {
for (int i = 0; i < step; i++) {
float startX = i * stepWidth + i * dividerWidth;
float endX = (i == step - 1) ? barWidth : ((i + 1) * stepWidth + (i + 1) * dividerWidth);
if (x > startX && x <= endX) {
curStep = i + 1;
invalidate();
break;
}
}
}
//获取当前步阶
public int getCurStep() {
return curStep;
}
public void setOnDragStepListener(OnDragStepListener onDragStepListener) {
this.onDragStepListener = onDragStepListener;
}
///设置默认步阶
public void setDefaultStep(int step) {
curStep = step;
invalidate();
}
public interface OnDragStepListener {
void onDragStep(int step, boolean moveCancel);
}
}
在项目style.xml添加基本属性:
<declare-styleable name="DragStepBar">
<!--渐变色开始色-->
<attr name="bar_color_start" format="color"/>
<!--渐变色结束色-->
<attr name="bar_color_end" format="color"/>
<!--进度条背景色-->
<attr name="bar_bg" format="color"/>
<!--分割线颜色-->
<attr name="bar_divider_color" format="color"/>
<!--分割线宽度-->
<attr name="bar_divider_width" format="dimension"/>
<!--总步数-->
<attr name="bar_step_count" format="integer"/>
<!--当前所在步数-->
<attr name="bar_cur_step" format="integer"/>
</declare-styleable>
布局中使用:
<com.study.android.diyviewdemo.DragStepBar
android:layout_width="wrap_content"
android:layout_height="28dp"
android:layout_marginTop="20dp"
android:layout_marginStart="10dp"
app:bar_step_count="5"
app:bar_cur_step="3"
app:bar_divider_width="1dp"
android:paddingStart="16dp" />
完成