软件编程
位置:首页>> 软件编程>> Android编程>> Android编程基于自定义View实现绚丽的圆形进度条功能示例

Android编程基于自定义View实现绚丽的圆形进度条功能示例

作者:books1958  发布时间:2023-07-24 17:13:26 

标签:Android,自定义,View,进度条

本文实例讲述了Android编程基于自定义View实现绚丽的圆形进度条功能。分享给大家供大家参考,具体如下:

本文包含两个组件,首先上效果图:

1.ProgressBarView1(支持拖动):

Android编程基于自定义View实现绚丽的圆形进度条功能示例

2.ProgressBarView2(不同进度值显示不同颜色,不支持拖拽):

Android编程基于自定义View实现绚丽的圆形进度条功能示例 Android编程基于自定义View实现绚丽的圆形进度条功能示例

代码不多,注释也比较详细,全部贴上了:

(一)ProgressBarView1:


/**
* 自定义绚丽的ProgressBar.
*/
public class ProgressBarView1 extends View {
 /**
  * 进度条所占用的角度
  */
 private static final int ARC_FULL_DEGREE = 300;
 /**
  * 弧线的宽度
  */
 private int STROKE_WIDTH;
 /**
  * 组件的宽,高
  */
 private int width, height;
 /**
  * 进度条最大值和当前进度值
  */
 private float max, progress;
 /**
  * 是否允许拖动进度条
  */
 private boolean draggingEnabled = false;
 /**
  * 绘制弧线的矩形区域
  */
 private RectF circleRectF;
 /**
  * 绘制弧线的画笔
  */
 private Paint progressPaint;
 /**
  * 绘制文字的画笔
  */
 private Paint textPaint;
 /**
  * 绘制当前进度值的画笔
  */
 private Paint thumbPaint;
 /**
  * 圆弧的半径
  */
 private int circleRadius;
 /**
  * 圆弧圆心位置
  */
 private int centerX, centerY;
 public ProgressBarView1(Context context) {
   super(context);
   init();
 }
 public ProgressBarView1(Context context, AttributeSet attrs) {
   super(context, attrs);
   init();
 }
 public ProgressBarView1(Context context, AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);
   init();
 }
 private void init() {
   progressPaint = new Paint();
   progressPaint.setAntiAlias(true);
   textPaint = new Paint();
   textPaint.setColor(Color.WHITE);
   textPaint.setAntiAlias(true);
   thumbPaint = new Paint();
   thumbPaint.setAntiAlias(true);
   //使用自定义字体
   textPaint.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fangz.ttf"));
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   if (width == 0 || height == 0) {
     width = getWidth();
     height = getHeight();
     //计算圆弧半径和圆心点
     circleRadius = Math.min(width, height) / 2;
     STROKE_WIDTH = circleRadius / 12;
     circleRadius -= STROKE_WIDTH;
     centerX = width / 2;
     centerY = height / 2;
     //圆弧所在矩形区域
     circleRectF = new RectF();
     circleRectF.left = centerX - circleRadius;
     circleRectF.top = centerY - circleRadius;
     circleRectF.right = centerX + circleRadius;
     circleRectF.bottom = centerY + circleRadius;
   }
 }
 private Rect textBounds = new Rect();
 @Override
 protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);
   float start = 90 + ((360 - ARC_FULL_DEGREE) >> 1); //进度条起始点
   float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度
   float sweep2 = ARC_FULL_DEGREE - sweep1; //剩余的角度
   //绘制起始位置小圆形
   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);
   canvas.drawCircle(startX, startY, STROKE_WIDTH / 2, progressPaint);
   //绘制进度条
   progressPaint.setStrokeWidth(STROKE_WIDTH);
   progressPaint.setStyle(Paint.Style.STROKE);//设置空心
   canvas.drawArc(circleRectF, start, sweep1, false, progressPaint);
   //绘制进度条背景
   progressPaint.setColor(Color.parseColor("#d64444"));
   canvas.drawArc(circleRectF, start + sweep1, sweep2, false, progressPaint);
   //绘制结束位置小圆形
   progressPaint.setStrokeWidth(0);
   progressPaint.setStyle(Paint.Style.FILL);
   float endX = centerX + circleRadius * (float) Math.sin(radians);
   float endY = centerY + circleRadius * (float) Math.cos(radians);
   canvas.drawCircle(endX, endY, STROKE_WIDTH / 2, progressPaint);
   //上一行文字
   textPaint.setTextSize(circleRadius >> 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);
   //百分号
   textPaint.setTextSize(circleRadius >> 2);
   canvas.drawText("%", centerX + textLen / 2 + extra + 5, centerY - 30 + h1 / 2, textPaint);
   //下一行文字
   textPaint.setTextSize(circleRadius / 5);
   text = "可用内存充足";
   textLen = textPaint.measureText(text);
   textPaint.getTextBounds(text, 0, text.length(), textBounds);
   float h2 = textBounds.height();
   canvas.drawText(text, centerX - textLen / 2, centerY + h1 / 2 + h2, textPaint);
   //绘制进度位置,也可以直接替换成一张图片
   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);
   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);
 }
 private boolean isDragging = false;
 @Override
 public boolean onTouchEvent(@NonNull MotionEvent event) {
   if (!draggingEnabled) {
     return super.onTouchEvent(event);
   }
   //处理拖动事件
   float currentX = event.getX();
   float currentY = event.getY();
   int action = event.getAction();
   switch (action) {
     case MotionEvent.ACTION_DOWN:
       //判断是否在进度条thumb位置
       if (checkOnArc(currentX, currentY)) {
         float newProgress = calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max;
         setProgressSync(newProgress);
         isDragging = true;
       }
       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;
 }
 private float calDistance(float x1, float y1, float x2, float y2) {
   return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
 }
 /**
  * 判断该点是否在弧线上(附近)
  */
 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);
 }
 /**
  * 根据当前位置,计算出进度条已经转过的角度。
  */
 private float calDegreeByPosition(float currentX, float currentY) {
   float a1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI * 180);
   if (currentY < centerY) {
     a1 += 180;
   } else if (currentY > centerY && currentX > centerX) {
     a1 += 360;
   }
   return a1 - (360 - ARC_FULL_DEGREE) / 2;
 }
 public void setMax(int max) {
   this.max = max;
   invalidate();
 }
 public void setProgress(float progress) {
   final float validProgress = checkProgress(progress);
   //动画切换进度值
   new Thread(new Runnable() {
     @Override
     public void run() {
       float oldProgress = ProgressBarView1.this.progress;
       for (int i = 1; i <= 100; i++) {
         ProgressBarView1.this.progress = oldProgress + (validProgress - oldProgress) * (1.0f * i / 100);
         postInvalidate();
         SystemClock.sleep(20);
       }
     }
   }).start();
 }
 public void setProgressSync(float progress) {
   this.progress = checkProgress(progress);
   invalidate();
 }
 //保证progress的值位于[0,max]
 private float checkProgress(float progress) {
   if (progress < 0) {
     return 0;
   }
   return progress > max ? max : progress;
 }
 public void setDraggingEnabled(boolean draggingEnabled) {
   this.draggingEnabled = draggingEnabled;
 }
}

(二)ProgressBarView2:


/**
* 自定义绚丽的ProgressBar.
*/
public class ProgressBarView2 extends View {
 /**
  * 进度条所占用的角度
  */
 private static final int ARC_FULL_DEGREE = 300;
 //进度条个数
 private static final int COUNT = 100;
 //每个进度条所占用角度
 private static final float ARC_EACH_PROGRESS = ARC_FULL_DEGREE * 1.0f / (COUNT - 1);
 /**
  * 弧线细线条的长度
  */
 private int ARC_LINE_LENGTH;
 /**
  * 弧线细线条的宽度
  */
 private int ARC_LINE_WIDTH;
 /**
  * 组件的宽,高
  */
 private int width, height;
 /**
  * 进度条最大值和当前进度值
  */
 private float max, progress;
 /**
  * 绘制弧线的画笔
  */
 private Paint progressPaint;
 /**
  * 绘制文字的画笔
  */
 private Paint textPaint;
 /**
  * 绘制文字背景圆形的画笔
  */
 private Paint textBgPaint;
 /**
  * 圆弧的半径
  */
 private int circleRadius;
 /**
  * 圆弧圆心位置
  */
 private int centerX, centerY;
 public ProgressBarView2(Context context) {
   super(context);
   init();
 }
 public ProgressBarView2(Context context, AttributeSet attrs) {
   super(context, attrs);
   init();
 }
 public ProgressBarView2(Context context, AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);
   init();
 }
 private void init() {
   progressPaint = new Paint();
   progressPaint.setAntiAlias(true);
   textPaint = new Paint();
   textPaint.setColor(Color.WHITE);
   textPaint.setAntiAlias(true);
   textBgPaint = new Paint();
   textBgPaint.setAntiAlias(true);
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   if (width == 0 || height == 0) {
     width = getWidth();
     height = getHeight();
     //计算圆弧半径和圆心点
     circleRadius = Math.min(width, height) / 2;
     ARC_LINE_LENGTH = circleRadius / 6;
     ARC_LINE_WIDTH = ARC_LINE_LENGTH / 8;
     centerX = width / 2;
     centerY = height / 2;
   }
 }
 private Rect textBounds = new Rect();
 @Override
 protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);
   float start = (360 - ARC_FULL_DEGREE) >> 1; //进度条起始角度
   float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度
   //绘制进度条
   progressPaint.setColor(Color.parseColor(calColor(progress / max, "#ffff0000", "#ff00ff00")));
   progressPaint.setStrokeWidth(ARC_LINE_WIDTH);
   float drawDegree = 1.6f;
   while (drawDegree <= ARC_FULL_DEGREE) {
     double a = (start + drawDegree) / 180 * Math.PI;
     float lineStartX = centerX - circleRadius * (float) Math.sin(a);
     float lineStartY = centerY + circleRadius * (float) Math.cos(a);
     float lineStopX = lineStartX + ARC_LINE_LENGTH * (float) Math.sin(a);
     float lineStopY = lineStartY - ARC_LINE_LENGTH * (float) Math.cos(a);
     if (drawDegree > sweep1) {
       //绘制进度条背景
       progressPaint.setColor(Color.parseColor("#88aaaaaa"));
       progressPaint.setStrokeWidth(ARC_LINE_WIDTH >> 1);
     }
     canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, progressPaint);
     drawDegree += ARC_EACH_PROGRESS;
   }
   //绘制文字背景圆形
   textBgPaint.setStyle(Paint.Style.FILL);//设置填充
   textBgPaint.setColor(Color.parseColor("#41668b"));
   canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) * 0.8f, textBgPaint);
   textBgPaint.setStyle(Paint.Style.STROKE);//设置空心
   textBgPaint.setStrokeWidth(2);
   textBgPaint.setColor(Color.parseColor("#aaaaaaaa"));
   canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) * 0.8f, textBgPaint);
   //上一行文字
   textPaint.setTextSize(circleRadius >> 1);
   String text = (int) (100 * progress / max) + "";
   float textLen = textPaint.measureText(text);
   //计算文字高度
   textPaint.getTextBounds("8", 0, 1, textBounds);
   float h1 = textBounds.height();
   canvas.drawText(text, centerX - textLen / 2, centerY - circleRadius / 10 + h1 / 2, textPaint);
   //分
   textPaint.setTextSize(circleRadius >> 3);
   textPaint.getTextBounds("分", 0, 1, textBounds);
   float h11 = textBounds.height();
   canvas.drawText("分", centerX + textLen / 2 + 5, centerY - circleRadius / 10 + h1 / 2 - (h1 - h11), textPaint);
   //下一行文字
   textPaint.setTextSize(circleRadius / 6);
   text = "点击优化";
   textLen = textPaint.measureText(text);
   canvas.drawText(text, centerX - textLen / 2, centerY + circleRadius / 2.5f, textPaint);
 }
 public void setMax(int max) {
   this.max = max;
   invalidate();
 }
 //动画切换进度值(异步)
 public void setProgress(final float progress) {
   new Thread(new Runnable() {
     @Override
     public void run() {
       float oldProgress = ProgressBarView2.this.progress;
       for (int i = 1; i <= 100; i++) {
         ProgressBarView2.this.progress = oldProgress + (progress - oldProgress) * (1.0f * i / 100);
         postInvalidate();
         SystemClock.sleep(20);
       }
     }
   }).start();
 }
 //直接设置进度值(同步)
 public void setProgressSync(float progress) {
   this.progress = progress;
   invalidate();
 }
 /**
  * 计算渐变效果中间的某个颜色值。
  * 仅支持 #aarrggbb 模式,例如 #ccc9c9b2
  */
 public String calColor(float fraction, String startValue, String endValue) {
   int start_a, start_r, start_g, start_b;
   int end_a, end_r, end_g, end_b;
   //start
   start_a = getIntValue(startValue, 1, 3);
   start_r = getIntValue(startValue, 3, 5);
   start_g = getIntValue(startValue, 5, 7);
   start_b = getIntValue(startValue, 7, 9);
   //end
   end_a = getIntValue(endValue, 1, 3);
   end_r = getIntValue(endValue, 3, 5);
   end_g = getIntValue(endValue, 5, 7);
   end_b = getIntValue(endValue, 7, 9);
   return "#" + getHexString((int) (start_a + fraction * (end_a - start_a)))
       + getHexString((int) (start_r + fraction * (end_r - start_r)))
       + getHexString((int) (start_g + fraction * (end_g - start_g)))
       + getHexString((int) (start_b + fraction * (end_b - start_b)));
 }
 //从原始#AARRGGBB颜色值中指定位置截取,并转为int.
 private int getIntValue(String hexValue, int start, int end) {
   return Integer.parseInt(hexValue.substring(start, end), 16);
 }
 private String getHexString(int value) {
   String a = Integer.toHexString(value);
   if (a.length() == 1) {
     a = "0" + a;
   }
   return a;
 }
}

希望本文所述对大家Android程序设计有所帮助。

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com