Android绘制圆形百分比加载圈效果

先看一组加载效果图,有点粉粉的加载圈:

自定义这样的圆形加载圈还是比较简单的,主要是用到Canvans的绘制文本,绘制圆和绘制圆弧的api:

/**
 * 绘制圆
 * @param cx   圆心x坐标
 * @param cy   圆心y坐标
 * @param radius 圆的半径
 * @param paint 画笔
 */
 public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
 ...
 }

/**
 * 绘制圆弧
 * @param oval    决定圆弧范围的矩形区域
 * @param startAngle 开始角度
 * @param sweepAngle 绘制的角度
 * @param useCenter 是否需要连接圆心,true连接,false不连接
 * @param paint   画笔
 */
 public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint) {
  ...
 }

 /**
  * 绘制文本
  * @param text 需要绘制的字符串
  * @param x   绘制文本起点x坐标,注意文本比较特殊,它的起点是左下角的x坐标
  * @param y   绘制文本起点y坐标,同样是左下角的y坐标
  * @param paint 画笔
  */
 public void drawText(String text, float x, float y, Paint paint) {
  ...
 }

开始绘图前需要考虑的以下几点:

1.获取控件的宽和高,这个是决定圆的半径大小的,半径大小等于宽高的最小值的1/2,为什么是最小值呢?因为这样就不会受布局文件中宽高属性不一样的影响,当然我们自己在使用的时候肯定是宽高都是会写成一样的,这样就刚好是一个正方形,绘制出来的圆就刚好在该正方形区域内.做了这样的处理,其他人在用的时候就不用当心圆会不会超出控件范围的情况了.

2.确定圆心的坐标,有了半径和圆心坐标就可以确定一个圆了,布局中的控件区域其实都是一个矩形区域,如果想要绘制出来的圆刚好处于控件的矩形区域内并且和矩形的最短的那条边相切,那么圆心坐标的就是该矩形宽高的1/2,即刚好位于矩形区域的中心点.

3.绘制圆弧,注意这里的圆弧指的是进度圈,看上面的示例图是有2种样式,分别是实心的加载圈和空心加载圈,这个其实就是paint的样式决定,如果是实心圆,paint设置为Paint.Style.FILL(填充模式),同时drawArc的useCenter设置为true;如果是空心圆则paint设置为Paint.Style.STROKE(线性模式),同时drawArc的useCenter设置为false即可.值得一提的是绘制空心圆的时候还需要考虑圆弧的宽度,宽度有多大将决定进度圈的厚度.因此在定义空心圆的矩形区域的时候需要减去进度圈的厚度,否则画出来的进度圈会超出控件的区域.

4.绘制文本,需要定位起始点,文本的起始点比较特殊,它是以左下角为起始点的,起点x坐标=圆心x坐标-文本宽度1/2;起始点y坐标=圆心y坐标+文本高度1/2;至于文本的宽高获取可以通过paint的getTextBounds()方法获取,具体等下看代码.

ok,直接上代码,注释已经很详细了.

圆形加载圈

public class CircleProgressView extends View {
  private int width;//控件宽度
  private int height;//控件高
  private float radius;//半径
  private float pointX;//圆心x坐标
  private float pointY;//圆心y坐标
  private int circleBackgroundColor;//背景颜色
  private int circleBackgroundAlpha; //背景透明度
  private int circleRingColor;//进度颜色
  private int progressTextColor;//进度文本的颜色
  private int progressTextSize;//进度文本的字体大小
  private int circleRingWidth; //进度的宽度
  private Paint mPaint;
  private int progress;//进度值
  private boolean isRingStyle;//是否是空心的圆环进度样式

  public CircleProgressView(Context context) {
    this(context, null);
  }

  public CircleProgressView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    circleBackgroundColor = Color.WHITE;
    circleRingColor = Color.parseColor("#3A91FF");
    progressTextColor = Color.BLACK;
    circleBackgroundAlpha = 128;
    progressTextSize = 32;
    circleRingWidth = 10;
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStyle(Paint.Style.FILL);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    width = getMeasuredWidth();
    height = getMeasuredHeight();
    radius = Math.min(width, height) / 2.0f;
    pointX = width / 2.0f;
    pointY = height / 2.0f;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    drawBackground(canvas);
    drawCircleRing(canvas);
    drawProgressText(canvas);
  }

  /**
   * 绘制背景色
   *
   * @param canvas
   */
  private void drawBackground(Canvas canvas) {
    mPaint.setColor(circleBackgroundColor);
    mPaint.setAlpha(circleBackgroundAlpha);
    canvas.drawCircle(pointX, pointY, radius, mPaint);
  }

  /**
   * 绘制圆环
   *
   * @param canvas
   */
  private void drawCircleRing(Canvas canvas) {
    mPaint.setColor(circleRingColor);
    RectF oval = new RectF();
    if (isRingStyle) {
      mPaint.setStyle(Paint.Style.STROKE);
      mPaint.setStrokeWidth(circleRingWidth);
      mPaint.setStrokeCap(Paint.Cap.ROUND);
      //注意:定义圆环的矩形区域是需要考虑圆环的宽度
      oval.left = circleRingWidth / 2.0f;
      oval.top = height / 2.0f - radius + circleRingWidth / 2.0f;
      oval.right = 2 * radius - circleRingWidth / 2.0f;
      oval.bottom = height / 2.0f + radius - circleRingWidth / 2.0f;
      canvas.drawArc(oval, 0, 360 * progress / 100, false, mPaint);
    } else {
      mPaint.setStyle(Paint.Style.FILL);
      oval.left = 0;
      oval.top = height / 2.0f - radius;
      oval.right = 2 * radius;
      oval.bottom = height / 2.0f + radius;
      canvas.drawArc(oval, 0, 360 * progress / 100, true, mPaint);
    }

  }

  /**
   * 绘制进度文本
   *
   * @param canvas
   */
  private void drawProgressText(Canvas canvas) {
    mPaint.setColor(progressTextColor);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setTextSize(progressTextSize);
    Rect textBound = new Rect();
    String text = progress + "%";
    //获取文本的矩形区域到textBound中
    mPaint.getTextBounds(text, 0, text.length(), textBound);
    int textWidth = textBound.width();
    int textHeight = textBound.height();
    float x = pointX - textWidth / 2.0f;
    float y = pointY + textHeight / 2.0f;
    canvas.drawText(text, x, y, mPaint);
  }

  /**
   * 更新进度
   *
   * @param progress
   */
  public void setValue(int progress) {
    this.progress = progress;
    invalidate();
  }

  /**
   * 设置进度圆环的样式
   *
   * @param isRing true是空心的圆环,false表示实心的圆环
   */
  public void setCircleRingStyle(boolean isRing) {
    this.isRingStyle = isRing;
  }

  /**
   * 设置背景透明度
   *
   * @param alpha 0~255
   */
  public void setCircleBackgroundAlpha(int alpha) {
    this.circleBackgroundAlpha = alpha;
  }

  /**
   * 设置进度文本的大小
   * @param progressTextSize
   */
  public void setProgressTextSize(int progressTextSize) {
    this.progressTextSize = progressTextSize;
  }

  /**
   * 设置进度文本的颜色
   * @param progressTextColor
   */
  public void setProgressTextColor(int progressTextColor) {
    this.progressTextColor = progressTextColor;
  }
}

测试类

public class MainActivity extends AppCompatActivity {
  private CircleProgressView mCircleProgressView;
  private int progress;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mCircleProgressView = (CircleProgressView) findViewById(R.id.progressView);
    mCircleProgressView.setCircleRingStyle(false);//实心圆
    HandlerThread thread = new HandlerThread("draw-thread");
    thread.start();
    Handler tHandler = new Handler(thread.getLooper()) {
      @Override
      public void handleMessage(Message msg) {
        runOnUiThread(new Runnable() {
          @Override
          public void run() {
            mCircleProgressView.setValue(progress++);

          }
        });
        if (progress <100) {
          sendEmptyMessageDelayed(0, 100);
        }
      }
    };
    tHandler.sendEmptyMessage(0);
  }
}

XML使用方式

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@color/colorAccent"
 tools:context="mchenys.net.csdn.blog.progressview.MainActivity">

 <mchenys.net.csdn.blog.progressview.CircleProgressView
 android:id="@+id/progressView"
 android:layout_width="100dp"
 android:layout_height="200dp"
 android:layout_centerInParent="true"
 />

</RelativeLayout>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android开发之绘制平面上的多边形功能分析

    本文实例讲述了Android开发之绘制平面上的多边形功能.分享给大家供大家参考,具体如下: 计算机里的3D图形其实是由很多个平面组合而成的.所谓"绘制3D"图形,其实是通过多个平面图形形成的.调用GL10图形绘制2D图形的步骤如下: i. 调用GL10的glEnableClientState(GL10.GL_VERTEX_ARRAY);方法启用顶点坐标数组. ii. 调用GL10的glEnableClientState(GL10.GL_COLOR_ARRAY);方法启用顶点颜色数组.

  • Android编程绘图操作之弧形绘制方法示例

    本文实例讲述了Android编程绘图操作之弧形绘制方法.分享给大家供大家参考,具体如下: /** * 绘制弧形图案 * @description: * @author ldm * @date 2016-4-25 下午4:37:01 */ public class ArcsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedIns

  • Android shape 绘制图形的实例详解

    Android shape 绘制图形 Android 绘制图形可以使用shape也可以使用自定义控件的方式,这里我们说下shape的方式去实现. 在绘制图形之前,我们先来了解下shape的几个属性. shape /* * 线行 圆形 矩形 / android:shape="line" android:shape="oval" android:shape="rectangle" size 图形的大小 <size android:height=

  • Android开发 OpenGL ES绘制3D 图形实例详解

    OpenGL ES是 OpenGL三维图形API 的子集,针对手机.PDA和游戏主机等嵌入式设备而设计. Ophone目前支持OpenGL ES 1.0 ,OpenGL ES 1.0 是以 OpenGL 1.3 规范为基础的,OpenGL ES 1.1 是以 OpenGL 1.5 规范为基础的.本文主要介绍利用OpenGL ES绘制图形方面的基本步骤. 本文内容由三部分构成.首先通过EGL获得OpenGL ES的编程接口;其次介绍构建3D程序的基本概念;最后是一个应用程序示例. OpenGL E

  • Android编程绘制圆形图片的方法

    本文实例讲述了Android编程绘制圆形图片的方法.分享给大家供大家参考,具体如下: 效果图如下: 第一步:新建RoundView自定义控件继承View package com.rong.activity; import com.rong.test.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.grap

  • Android自定义View之继承TextView绘制背景

    本文实例为大家分享了TextView绘制背景的方法,供大家参考,具体内容如下 效果: 实现流程: 1.初始化:对画笔进行设置 mPaintIn = new Paint(); mPaintIn.setAntiAlias(true); mPaintIn.setDither(true); mPaintIn.setStyle(Paint.Style.FILL); mPaintIn.setColor(getResources().getColor(R.color.colorPrimary)); mPain

  • Android开发之OpenGL绘制2D图形的方法分析

    本文实例讲述了Android开发之OpenGL绘制2D图形的方法.分享给大家供大家参考,具体如下: Android为OpenGL ES支持提供了GLSurviceView组建,这个组建用于显示3D图形.GLSurviceView本身并不提供绘制3的图形的功能,而是由GLSurfaceView.Renderer来完成了SurviceView中3D图形的绘制. 归纳起来,在android中使用OpenGL ES需要3个步骤. 1. 创建GLSurviceView组件,使用Activity来显示GLS

  • Android使用音频信息绘制动态波纹

    在一些音乐类应用中, 经常会展示随着节奏上下起伏的波纹信息, 这些波纹形象地传达了声音信息, 可以提升用户体验, 那么是如何实现的呢? 可以使用Visualizer类获取当前播放的声音信息, 并绘制在画布上, 使用波纹展示即可. 我来讲解一下使用方法. 主要 (1) Visualizer类提取波纹信息的方式. (2) 应用动态权限管理的方法. (3) 分离自定义视图的展示和逻辑. 1. 基础准备 Android 6.0引入动态权限管理, 在这个项目中, 会使用系统的音频信息, 因此把权限管理引入

  • Android编程之canvas绘制各种图形(点,直线,弧,圆,椭圆,文字,矩形,多边形,曲线,圆角矩形)

    本文实例讲述了Android编程之canvas绘制各种图形的方法.分享给大家供大家参考,具体如下: 1.首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into

  • Android中使用ListView绘制自定义表格技巧分享

    先上一下可以实现的效果图  要实现的效果有几方面 1.列不固定:可以根据数据源的不同生成不同的列数 2.表格内容可以根据数据源的定义合并列 3.要填写的单元格可以选择自定义键盘还是系统键盘 奔着这三点,做了个简单的实现,把源码贴一下(因为该点是主界面中的一部分,不便于放整个Demo) 自定义适配器,CallBackInterface是自定义的回调接口,这里定义回调是因为数据输入时需要及时保存 复制代码 代码如下: public class SiteDetailViewAdapter extend

  • 解决Android SurfaceView绘制触摸轨迹闪烁问题的方法

    本文分享了解决SurfaceView触摸轨迹闪烁问题的方法,供大家参考,具体内容如下 第一种解决SurfaceView触摸轨迹闪烁问题的方法: 由于SurfaceView使用双缓存机制,两张画布轮流显示到屏幕上.那么,要存储触摸轨迹并避免两张画布内容不一致造成的闪烁问题,完全可以利用保存绘制过程并不断重新绘制的方法解决闪烁,而且这样还顺带解决了多次试验中偶尔出现的因为moveTo()函数不能读取到参数执行默认设置(参数设为上次的触摸点)而出现的断线连接闪烁问题,详细代码如下: package c

  • Android编程实现扭曲图像的绘制功能示例

    本文实例讲述了Android编程实现扭曲图像的绘制功能.分享给大家供大家参考,具体如下: 为了实现动画效果,使用drawBitmapMess方法对图像进行扭曲,使用定时器以100毫秒的频率按圆形轨迹扭曲图像. 扭曲的关键是生成verts数组.本例一开始会先生成verts数组的初始值:有一定水平和垂直间距的网点坐标.然后通过warp方法按一定的数学方法变化verts数组中的坐标.关键部分的代码如下: 定义基本变量:MyView是用于显示扭曲的图像的自定义view,angle是圆形轨迹的当前角度:

随机推荐