Android开发中由于需求的不同会遇到各种各样的进度条,本文实现一个自定义手动控制的进度条,先来看一下效果:
2.通过滑动进度条上的按钮控制进度
如上展示效果可见,圆弧所跨弧度为270,其中可将绘制分为6个部分:
1.代码实现中各个属性的定义以及其作用:
/**
* 进度条所占用的角度
*/
private static final int ARC_FULL_DEGREE = 270;
/**
* 弧线的宽度
*/
private int STROKE_WIDTH;
/**
* 组件的宽,高
*/
private int width, height,sWidth,sHeight;
/**
* 进度条最大值和当前进度值
*/
private float max, progress;
/**
* 是否允许拖动进度条
*/
private boolean draggingEnabled = false;
/**
* 绘制弧线的矩形区域
*/
private RectF circleRectF,zhizhenRectF;
/**
* 绘制弧线的画笔
*/
private Paint progressPaint;
/**
* 绘制文字的画笔
*/
private Paint textPaint;
/**
* 绘制当前进度值的画笔
*/
private Paint thumbPaint;
/**
* 圆弧的半径
*/
private int circleRadius;
/**
* 圆弧圆心位置
*/
private int centerX, centerY;
private int upBtCenterX,upBtCenterY,downBtCenterx,downBtCenterY;//控制按钮的坐标
private Bitmap zhizhen;
private Matrix matrix;//矩阵--控制指针图片的动画
/**
* 指针圆心
*/
private float circleRectFCenterWidth;
private float circleRectFCenterHeight;
/**
* 圆弧上渐变色的颜色值
*/
private final int[] colors = {Color.parseColor("#FFF68F"),Color.parseColor("#FFE700")
,Color.parseColor("#FFD700"),Color.parseColor("#FFC700")
,Color.parseColor("#FFB700"),Color.parseColor("#FFA700")
,Color.parseColor("#FF9700"),Color.parseColor("#FF7F00")};
2.圆弧,控制按钮,以及其他显示的绘制:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e("ondraw", "测试2");
float start = 90 + ((360 - ARC_FULL_DEGREE) >> 1); //进度条起始点
float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度
float sweep2 = ARC_FULL_DEGREE - sweep1; //剩余的角度
float progressRadians = (float) (((360.0f - ARC_FULL_DEGREE) / 2 + sweep1) / 180 * Math.PI);
float thumbX = centerX - circleRadius * (float) Math.sin(progressRadians);
float thumbY = centerY + circleRadius * (float) Math.cos(progressRadians);
//绘制起始位置小圆形
progressPaint.setColor(Color.WHITE);
progressPaint.setStrokeWidth(0);
progressPaint.setStyle(Paint.Style.FILL);
float radians = (float) (((360.0f - ARC_FULL_DEGREE) / 2) / 180 * Math.PI);
float startX = centerX - circleRadius * (float) Math.sin(radians);
float startY = centerY + circleRadius * (float) Math.cos(radians);
System.out.println("startX=" + startX + ";startY="+ startY);
canvas.drawCircle(startX, startY, STROKE_WIDTH / 2, progressPaint);
//绘制控制进度减按钮
buttonRadius = circleRadius/8;
downBtCenterx=(int) (startX+buttonRadius);
downBtCenterY=(int) (startY+4*buttonRadius);
progressPaint.setColor(Color.parseColor("#8800FFFF"));
canvas.drawCircle(startX+buttonRadius, startY+4*buttonRadius, buttonRadius, progressPaint);
progressPaint.setColor(Color.parseColor("#F0FFFF"));
progressPaint.setStrokeWidth(5);
canvas.drawLine(startX+buttonRadius-buttonRadius*3/4, startY+4*buttonRadius, startX+buttonRadius+buttonRadius*3/4, startY+4*buttonRadius, progressPaint);
Log.e("onDraw", "测试-画圆");
//绘制进度条
for(int i=0;i> 1);
String text = (int) (100 * progress / max) + "";
float textLen = textPaint.measureText(text);
//计算文字高度
textPaint.getTextBounds("8", 0, 1, textBounds);
float h1 = textBounds.height();
//% 前面的数字水平居中,适当调整
float extra = text.startsWith("1") ? -textPaint.measureText("1") / 2 : 0;
canvas.drawText(text, centerX - textLen / 2 + extra, centerY - 30 + h1 / 2, textPaint);
//绘制进度条上的按钮
thumbPaint.setColor(Color.parseColor("#33d64444"));
canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 2.0f, thumbPaint);
thumbPaint.setColor(Color.parseColor("#99d64444"));
canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 1.4f, thumbPaint);
thumbPaint.setColor(Color.WHITE);
canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 0.8f, thumbPaint);
Log.e("onDraw", "测试-完成");
System.out.println("进度值progress="+progress);
}
3.点击事件的实现:
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
if (!draggingEnabled) {
return super.onTouchEvent(event);
}
Log.e("onTouchEvent", "测试3");
//处理拖动事件
float currentX = event.getX();
float currentY = event.getY();
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
//判断是否在进度条thumb位置
if (checkOnArc(currentX, currentY)) {
newProgress = calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max;
setProgressSync(newProgress);
isDragging = true;
} else if(checkOnButtonUp(currentX, currentY)){
// TODO Auto-generated method stub
setProgress(progress+10);
isDragging = false;
}else if(checkOnButtonDwon(currentX, currentY)){
setProgress(progress-10);
isDragging = false;
}
break;
case MotionEvent.ACTION_MOVE:
if (isDragging) {
//判断拖动时是否移出去了
if (checkOnArc(currentX, currentY)) {
setProgressSync(calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max);
} else {
isDragging = false;
}
}
break;
case MotionEvent.ACTION_UP:
isDragging = false;
break;
}
return true;
}
点击事件中,分别对ACTION_DOWN事件,ACTION_UP事件和ACTION_MOVE事件进行了处理,当控制进度条的时候,需要判断点击事件是否在控制区域,所以,此时需要设置点击响应区域,该区域在圆弧上,圆弧控制上的按钮和控制按钮可适当扩大,防止点击时候点击不准确从而导致不能触发点击事件。除此之外,还需要注意在这几个部分扩大点击区域时,防止其中多个点击区域相交,导致点击该区域时,触发两个部分的点击事件。此处列出圆弧上点击区域的控制实现:
/**
* 判断该点是否在弧线上(附近)
*/
private boolean checkOnArc(float currentX, float currentY) {
float distance = calDistance(currentX, currentY, centerX, centerY);
float degree = calDegreeByPosition(currentX, currentY);
return distance > circleRadius - STROKE_WIDTH * 5 && distance < circleRadius + STROKE_WIDTH * 5
&& (degree >= -8 && degree <= ARC_FULL_DEGREE + 8);
}
https://download.csdn.net/download/lanhao21/10308826