Android高级UI开发(三十九)绘制圆环和圆弧进度

举报
yd_57386892 发表于 2020/12/29 00:12:11 2020/12/29
【摘要】 今天我们用Paint,Canvas在自定义View中绘制一个圆环,点击圆环后自动在圆环上绘制弧形进度,示意图如下:1. 我们先看一下页面布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" an...

  
  1. 今天我们用Paint,Canvas在自定义View中绘制一个圆环,点击圆环后自动在圆环上绘制弧形进度,示意图如下:
  2. 1. 我们先看一下页面布局文件:

  
  1. <RelativeLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:paddingBottom="16dp"
  6. android:paddingLeft="16dp"
  7. android:paddingRight="16dp"
  8. android:paddingTop="16dp"
  9. xmlns:app="http://schemas.android.com/apk/res-auto">
  10. <com.draw.draw_circleprogressbar.CircleProgressBar
  11. android:id="@+id/progressbar"
  12. android:layout_width="200dp"
  13. android:layout_height="200dp"
  14. app:roundProgressColor="#ff00ff"
  15. app:textColor="#000066"
  16. app:textSize="20dp"
  17. app:roundWidth="15dp"
  18. />
  19. </RelativeLayout>

  
  1. 其中CircleProgressBar是我们自定义的View,刚开始绘制一个圆环,点击View会绘制弧形进度。接下来我们先看一下它在MainActivity的用法。
  2. 2. CircleProgressBar在MainActivity中的使用
  3. MainActivity.java代码如下:

  
  1. package com.draw.draw_circleprogressbar;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. public class MainActivity extends AppCompatActivity {
  6. private CircleProgressBar mProgressbar;
  7. private int progress = 0;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView( R.layout.activity_main);
  12. mProgressbar = (CircleProgressBar) findViewById(R.id.progressbar);
  13. mProgressbar.setOnClickListener(new View.OnClickListener() {
  14. @Override
  15. public void onClick(View v) {
  16. new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. while (progress <= 100){
  20. progress += 2;
  21. mProgressbar.setProgress(progress);
  22. try {
  23. Thread.sleep(100);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }
  29. }).start();
  30. }
  31. });
  32. }
  33. }

  
  1. mProgressbar.setOnClickListener里我们每隔100ms让进度+2.很简单在这里不再赘述。
  2. 接下来我们详细了解下CircleProgressBar是如何自定义的。
  3. 3. 自定义控件CircleProgressBar
  4. CircleProgressBar.java如下:

  
  1. package com.draw.draw_circleprogressbar;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.graphics.Canvas;
  5. import android.graphics.Color;
  6. import android.graphics.Paint;
  7. import android.graphics.RectF;
  8. import android.graphics.Typeface;
  9. import android.support.annotation.Nullable;
  10. import android.util.AttributeSet;
  11. import android.view.View;
  12. /**
  13. * Created by xw modify on 2018/5/8.
  14. */
  15. public class CircleProgressBar extends View{
  16. private int max;
  17. private int roundColor;
  18. private int roundProgressColor;
  19. private int textColor;
  20. private float textSize;
  21. private float roundWidth;
  22. private boolean textShow;
  23. private int progress;
  24. private Paint paint;
  25. public static final int STROKE = 0;
  26. public static final int FILL = 1;
  27. public CircleProgressBar(Context context, @Nullable AttributeSet attrs) {
  28. super(context, attrs);
  29. paint = new Paint();
  30. TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar);
  31. max = typedArray.getInteger(R.styleable.CustomProgressBar_max, 100);
  32. roundColor = typedArray.getColor(R.styleable.CustomProgressBar_roundColor, Color.RED);
  33. roundProgressColor = typedArray.getColor(R.styleable.CustomProgressBar_roundProgressColor, Color.BLUE);
  34. textColor = typedArray.getColor(R.styleable.CustomProgressBar_textColor, Color.GREEN);
  35. textSize = typedArray.getDimension(R.styleable.CustomProgressBar_textSize, 55);
  36. roundWidth = typedArray.getDimension(R.styleable.CustomProgressBar_roundWidth, 10);
  37. textShow = typedArray.getBoolean(R.styleable.CustomProgressBar_textShow, true);
  38. typedArray.recycle();
  39. }
  40. @Override
  41. protected void onDraw(Canvas canvas) {
  42. super.onDraw(canvas);
  43. //画背景圆环
  44. int center = getWidth() / 2;
  45. float radius = center - roundWidth / 2;
  46. paint.setColor(roundColor);
  47. paint.setStyle(Paint.Style.STROKE);
  48. paint.setStrokeWidth(roundWidth); // 圆环的宽度
  49. paint.setAntiAlias(true);
  50. canvas.drawCircle(center,center,radius,paint);
  51. // 画进度百分比
  52. paint.setColor(textColor);
  53. paint.setStrokeWidth(0);
  54. paint.setTextSize(textSize);
  55. paint.setTypeface(Typeface.DEFAULT_BOLD);
  56. int percent = (int)(progress / (float)max * 100);
  57. String strPercent = percent + "%";
  58. Paint.FontMetricsInt fm = paint.getFontMetricsInt();
  59. if(percent != 0){
  60. canvas.drawText(strPercent, getWidth() / 2 - paint.measureText(strPercent) / 2 ,
  61. getWidth() / 2 +(fm.bottom - fm.top)/2 - fm.bottom, paint);
  62. }
  63. // 画圆弧
  64. RectF oval = new RectF(center - radius, center - radius,
  65. center + radius, center + radius);
  66. paint.setColor(roundProgressColor);
  67. paint.setStrokeWidth(roundWidth);
  68. paint.setStyle(Paint.Style.STROKE);
  69. paint.setStrokeCap(Paint.Cap.ROUND);
  70. canvas.drawArc(oval, 0 , 360 * progress / max, false, paint);
  71. }
  72. public void setProgress(int progress){
  73. if(progress < 0 ){
  74. throw new IllegalArgumentException("进度Progress不能小于0");
  75. }
  76. if(progress > max){
  77. progress = max;
  78. }
  79. if(progress <= max){
  80. this.progress = progress;
  81. postInvalidate();
  82. }
  83. }
  84. }

  
  1. 首先在CircleProgressBar构造函数里读取XML属性,比如roundColor圆环颜色,
  2. roundProgressColor圆弧进度的颜色,textColor圆中心文字的颜色,textSize文字大小,
  3. roundWidth圆环的宽度。接下来我们分析核心代码onDraw函数,
  4. 它总共分为3部分:绘制圆环、绘制文字、绘制圆弧进度
  5. 3.1 绘制圆环
  6. //画背景圆环
  7. int center = getWidth() / 2;
  8. float radius = center - roundWidth / 2;
  9. paint.setColor(roundColor);
  10. paint.setStyle(Paint.Style.STROKE);
  11. paint.setStrokeWidth(roundWidth); // 圆环的宽度
  12. paint.setAntiAlias(true);
  13. canvas.drawCircle(center,center,radius,paint);
  14. canvas.drawCircle(center,center,radius,paint);函数,
  15. 参数:center,center圆心的x,y坐标,即这个自定义控件View的中心,getWidth() / 2;
  16. 参数:radius:园的半径,
  17. getWidth() / 2 - roundWidth / 2 = center - roundWidth / 2;
  18. 即圆的半径是指从圆心 到 园环(园周)宽度中心的距离。
  19. 参数:paint: 画笔,在这里设置了画笔的颜色,风格为STROKE模式,圆环宽度,抗锯齿等。
  20. 3.2 绘制文字

  
  1. // 画进度百分比
  2. paint.setColor(textColor);
  3. paint.setStrokeWidth(0);
  4. paint.setTextSize(textSize);
  5. paint.setTypeface(Typeface.DEFAULT_BOLD);
  6. int percent = (int)(progress / (float)max * 100);
  7. String strPercent = percent + "%";
  8. Paint.FontMetricsInt fm = paint.getFontMetricsInt();
  9. if(percent != 0){
  10. canvas.drawText(strPercent, getWidth() / 2 - paint.measureText(strPercent) / 2 ,
  11. getWidth() / 2 +(fm.bottom - fm.top)/2 - fm.bottom, paint);
  12. }

  
  1. 这里主要看一下canvas.drawText的各参数:
  2. strPercent:要绘制的文本内容如“70%”;
  3. x: 文字相对于View的水平位置,即圆的中心getWidth() / 2 ,放在中心位置还不对,因为x代表的是文本的最左边的x坐标,要想文字居中,
  4. 还得用getWidth() / 2- paint.measureText(strPercent) / 2 ,即园心位置 在往左偏移 文本内容的一半宽度。
  5. y: 表示文本strPercent的基线Y坐标。我们称它为baseline。其实文本除了有基线,还有其它4条表示文本位置的线,如下图所示。
  6. 这里我们需要计算baseline,公式是:baseline = center +(FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom
  7. 其中center是文本内容的垂直中分线的y坐标(相对于View的顶端的y坐标),如上图中的center所示。
  8. 3.3 绘制圆弧进度
  9. paint.setStrokeCap(Paint.Cap.ROUND);
  10. 这个是设置笔帽的,比如你把铅笔头磨成方的还是圆的(线的两端点是圆头的),或者是尖的(正常情况下画出来就是直线)
  11. canvas.drawArc(oval, 0 , 360 * progress / max, false, paint);
  12. 绘制弧度,其中oval是一个rect,360 * progress / max是进度,false是不填充圆的内部区域,paint画笔。
  13. 3.4 设置进度setProgress
  14. 只有不断设置进度并调用postInvalidate函数才能出发onDraw函数重新绘制圆弧的进度。
  15. 好了,到此这个圆环和圆弧进度的动态绘制就讲完了。
  16.   源码:
https://download.csdn.net/download/gaoxiaoweiandy/12089175

文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/103887605

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。