当前位置:   article > 正文

Android自定义圆弧进度条,手动控制进度_android 自定义圆形可拖动进度条

android 自定义圆形可拖动进度条

一.展示

Android开发中由于需求的不同会遇到各种各样的进度条,本文实现一个自定义手动控制的进度条,先来看一下效果:

  1. 通过按钮控制进度条进度

2.通过滑动进度条上的按钮控制进度

二.实现

如上展示效果可见,圆弧所跨弧度为270,其中可将绘制分为6个部分:

  • 进度条的圆弧
  • 指针的图片
  • 圆弧上的控制按钮
  • 指针上显示进度详情的白色区域
  • 控制进度减的按钮
  • 控制进度加的按钮

1.代码实现中各个属性的定义以及其作用:

  1. /**
  2. * 进度条所占用的角度
  3. */
  4. private static final int ARC_FULL_DEGREE = 270;
  5. /**
  6. * 弧线的宽度
  7. */
  8. private int STROKE_WIDTH;
  9. /**
  10. * 组件的宽,高
  11. */
  12. private int width, height,sWidth,sHeight;
  13. /**
  14. * 进度条最大值和当前进度值
  15. */
  16. private float max, progress;
  17. /**
  18. * 是否允许拖动进度条
  19. */
  20. private boolean draggingEnabled = false;
  21. /**
  22. * 绘制弧线的矩形区域
  23. */
  24. private RectF circleRectF,zhizhenRectF;
  25. /**
  26. * 绘制弧线的画笔
  27. */
  28. private Paint progressPaint;
  29. /**
  30. * 绘制文字的画笔
  31. */
  32. private Paint textPaint;
  33. /**
  34. * 绘制当前进度值的画笔
  35. */
  36. private Paint thumbPaint;
  37. /**
  38. * 圆弧的半径
  39. */
  40. private int circleRadius;
  41. /**
  42. * 圆弧圆心位置
  43. */
  44. private int centerX, centerY;
  45. private int upBtCenterX,upBtCenterY,downBtCenterx,downBtCenterY;//控制按钮的坐标
  46. private Bitmap zhizhen;
  47. private Matrix matrix;//矩阵--控制指针图片的动画
  48. /**
  49. * 指针圆心
  50. */
  51. private float circleRectFCenterWidth;
  52. private float circleRectFCenterHeight;
  53. /**
  54. * 圆弧上渐变色的颜色值
  55. */
  56. private final int[] colors = {Color.parseColor("#FFF68F"),Color.parseColor("#FFE700")
  57. ,Color.parseColor("#FFD700"),Color.parseColor("#FFC700")
  58. ,Color.parseColor("#FFB700"),Color.parseColor("#FFA700")
  59. ,Color.parseColor("#FF9700"),Color.parseColor("#FF7F00")};

2.圆弧,控制按钮,以及其他显示的绘制:

  1.  protected void onDraw(Canvas canvas) {  
  2.         super.onDraw(canvas);  
  3.         Log.e("ondraw", "测试2");
  4.  
  5.         float start = 90 + ((360 - ARC_FULL_DEGREE) >> 1); //进度条起始点  
  6.         float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度  
  7.         float sweep2 = ARC_FULL_DEGREE - sweep1; //剩余的角度  
  8.         float progressRadians = (float) (((360.0f - ARC_FULL_DEGREE) / 2 + sweep1) / 180 * Math.PI);
  9.         float thumbX = centerX - circleRadius * (float) Math.sin(progressRadians);  
  10.         float thumbY = centerY + circleRadius * (float) Math.cos(progressRadians);
  11.  
  12.         //绘制起始位置小圆形  
  13.         progressPaint.setColor(Color.WHITE);  
  14.         progressPaint.setStrokeWidth(0);  
  15.         progressPaint.setStyle(Paint.Style.FILL);  
  16.         float radians = (float) (((360.0f - ARC_FULL_DEGREE) / 2) / 180 * Math.PI);  
  17.         float startX = centerX - circleRadius * (float) Math.sin(radians);  
  18.         float startY = centerY + circleRadius * (float) Math.cos(radians);  
  19.         System.out.println("startX=" + startX + ";startY="+ startY);
  20.         canvas.drawCircle(startX, startY, STROKE_WIDTH / 2, progressPaint);  
  21.         
  22.         //绘制控制进度减按钮
  23.         buttonRadius = circleRadius/8;
  24.         downBtCenterx=(int) (startX+buttonRadius);
  25.         downBtCenterY=(int) (startY+4*buttonRadius);
  26.         progressPaint.setColor(Color.parseColor("#8800FFFF"));
  27.         canvas.drawCircle(startX+buttonRadius, startY+4*buttonRadius, buttonRadius, progressPaint);
  28.         progressPaint.setColor(Color.parseColor("#F0FFFF"));
  29.         progressPaint.setStrokeWidth(5);
  30.         canvas.drawLine(startX+buttonRadius-buttonRadius*3/4, startY+4*buttonRadius, startX+buttonRadius+buttonRadius*3/4, startY+4*buttonRadius, progressPaint);
  31.         Log.e("onDraw", "测试-画圆");
  32.         //绘制进度条
  33.         for(int i=0;i<colors.length;i++){
  34.             position[i]=(float)(0.37+i*(progressRadians*100/360)/colors.length);
  35.         }
  36.         progressPaint.setStrokeWidth(STROKE_WIDTH);  
  37.         progressPaint.setStyle(Paint.Style.STROKE);//设置空心
  38.         LinearGradient linearGradient = new LinearGradient(startX, startY, thumbX, thumbY, colors, position, TileMode.CLAMP);
  39.         progressPaint.setShader(linearGradient);
  40.         canvas.drawArc(circleRectF, start, sweep1, false, progressPaint);  
  41.         //绘制进度条背景  
  42.         linearGradient=null;
  43.         progressPaint.setShader(null);
  44.         progressPaint.setColor(Color.parseColor("#d64444"));  
  45.         canvas.drawArc(circleRectF, start + sweep1, sweep2, false, progressPaint);  
  46.         Log.e("onDraw", "测试-画进度条");
  47.  
  48.         //绘制结束位置小圆形  
  49.         progressPaint.setStrokeWidth(0);  
  50.         progressPaint.setStyle(Paint.Style.FILL);  
  51.         float endX = centerX + circleRadius * (float) Math.sin(radians);  
  52.         float endY = centerY + circleRadius * (float) Math.cos(radians);  
  53.         canvas.drawCircle(endX, endY, STROKE_WIDTH / 2, progressPaint);  
  54.         Log.e("onDraw", "测试-画按钮");
  55.         
  56.       // 绘制进度加按钮
  57.         upBtCenterX=(int) (endX-buttonRadius);
  58.         upBtCenterY=(int) (endY+4*buttonRadius);
  59.         progressPaint.setColor(Color.parseColor("#8800FFFF"));
  60.         canvas.drawCircle(endX-buttonRadius, endY+4*buttonRadius, buttonRadius, progressPaint);
  61.         progressPaint.setColor(Color.parseColor("#F0FFFF"));
  62.         progressPaint.setStrokeWidth(5);
  63.         canvas.drawLine(endX-buttonRadius-buttonRadius*3/4, endY+4*buttonRadius, endX-buttonRadius+buttonRadius*3/4, endY+4*buttonRadius, progressPaint);
  64.         canvas.drawLine(endX-buttonRadius, endY+4*buttonRadius-buttonRadius*3/4, endX-buttonRadius, endY+4*buttonRadius+buttonRadius*3/4, progressPaint);
  65.         progressPaint.setColor(Color.WHITE);
  66.       //画出指针动画
  67.         matrix.reset();
  68.         matrix.postTranslate(circleRectFCenterWidth-width/2, circleRectFCenterHeight-height/2);
  69.         matrix.preRotate(40,width/2,height/2);
  70.         matrix.postRotate((float)(progressRadians*(180/Math.PI)),circleRectFCenterWidth, circleRectFCenterHeight);
  71.         System.out.println("宽="+ zhizhen.getWidth() + " 高=" + zhizhen.getHeight());
  72.         canvas.drawBitmap(zhizhen, matrix, progressPaint);
  73.         canvas.drawCircle(circleRectFCenterWidth, circleRectFCenterHeight, (float) (0.36*width), progressPaint);
  74.         
  75.         //上一行文字  
  76.         textPaint.setTextSize(circleRadius >> 1);  
  77.         String text = (int) (100 * progress / max) + "";  
  78.         float textLen = textPaint.measureText(text);  
  79.         //计算文字高度  
  80.         textPaint.getTextBounds("8", 0, 1, textBounds);  
  81.         float h1 = textBounds.height();  
  82.         //% 前面的数字水平居中,适当调整  
  83.         float extra = text.startsWith("1") ? -textPaint.measureText("1") / 2 : 0;  
  84.         canvas.drawText(text, centerX - textLen / 2 + extra, centerY - 30 + h1 / 2, textPaint);  
  85.         
  86.         //绘制进度条上的按钮
  87.         thumbPaint.setColor(Color.parseColor("#33d64444"));  
  88.         canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 2.0f, thumbPaint);  
  89.         thumbPaint.setColor(Color.parseColor("#99d64444"));  
  90.         canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 1.4f, thumbPaint);  
  91.         thumbPaint.setColor(Color.WHITE);  
  92.         canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH * 0.8f, thumbPaint);  
  93.         Log.e("onDraw", "测试-完成");
  94.         System.out.println("进度值progress="+progress);
  95.     } 

3.点击事件的实现:

  1. @Override
  2. public boolean onTouchEvent(@NonNull MotionEvent event) {
  3. if (!draggingEnabled) {
  4. return super.onTouchEvent(event);
  5. }
  6. Log.e("onTouchEvent", "测试3");
  7. //处理拖动事件
  8. float currentX = event.getX();
  9. float currentY = event.getY();
  10. int action = event.getAction();
  11. switch (action) {
  12. case MotionEvent.ACTION_DOWN:
  13. //判断是否在进度条thumb位置
  14. if (checkOnArc(currentX, currentY)) {
  15. newProgress = calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max;
  16. setProgressSync(newProgress);
  17. isDragging = true;
  18. } else if(checkOnButtonUp(currentX, currentY)){
  19. // TODO Auto-generated method stub
  20. setProgress(progress+10);
  21. isDragging = false;
  22. }else if(checkOnButtonDwon(currentX, currentY)){
  23. setProgress(progress-10);
  24. isDragging = false;
  25. }
  26. break;
  27. case MotionEvent.ACTION_MOVE:
  28. if (isDragging) {
  29. //判断拖动时是否移出去了
  30. if (checkOnArc(currentX, currentY)) {
  31. setProgressSync(calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max);
  32. } else {
  33. isDragging = false;
  34. }
  35. }
  36. break;
  37. case MotionEvent.ACTION_UP:
  38. isDragging = false;
  39. break;
  40. }
  41. return true;
  42. }

点击事件中,分别对ACTION_DOWN事件,ACTION_UP事件和ACTION_MOVE事件进行了处理,当控制进度条的时候,需要判断点击事件是否在控制区域,所以,此时需要设置点击响应区域,该区域在圆弧上,圆弧控制上的按钮和控制按钮可适当扩大,防止点击时候点击不准确从而导致不能触发点击事件。除此之外,还需要注意在这几个部分扩大点击区域时,防止其中多个点击区域相交,导致点击该区域时,触发两个部分的点击事件。此处列出圆弧上点击区域的控制实现:

  1. /**
  2. * 判断该点是否在弧线上(附近)
  3. */
  4. private boolean checkOnArc(float currentX, float currentY) {
  5. float distance = calDistance(currentX, currentY, centerX, centerY);
  6. float degree = calDegreeByPosition(currentX, currentY);
  7. return distance > circleRadius - STROKE_WIDTH * 5 && distance < circleRadius + STROKE_WIDTH * 5
  8. && (degree >= -8 && degree <= ARC_FULL_DEGREE + 8);
  9. }

三.源代码在此处:

https://download.csdn.net/download/lanhao21/10308826






声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/474149
推荐阅读
相关标签
  

闽ICP备14008679号