Android使用Canvas绘制圆形进度条效果

Android使用Canvas绘制圆形进度条效果,第1张

概述前言Android自定义控件经常会用到Canvas绘制2D图形,在优化自己自定义控件技能之前,必须熟练掌握Canvas绘图机制。本文从以下三个方面对Canvas绘图机制进行讲解:

前言

AndroID自定义控件经常会用到Canvas绘制2D图形,在优化自己自定义控件技能之前,必须熟练掌握Canvas绘图机制。本文从以下三个方面对Canvas绘图机制进行讲解:

画布Canvas
画笔Paint
示例圆形进度条

画布Canvas

首先,来看一下AndroID官网对Canvas类的定义:

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 the bitmap),a drawing primitive(eg,Rect,Path,text,Bitmap),and a paint(to describe the colors and styles for the drawing).

简单来说,AndroID进行2D绘图必须要有Canvas类的支持,它位于“androID.graphics.Canvas”包下。我们可以把Canvas理解成系统分配给我们的一块用于绘图的内存(ps:真正的内存是其包含的Bitmap)。

Canvas提供了两个构造函数:

Canvas() : 创建一个空的Canvas对象。
Canvas(Bitmap bitmap) : 创建一个以bitmap位图为背景的Canvas。
通常,我们会采用第二种包含Bitmap参数的构造函数方式或者直接使用onDraw方法中系统提供的Canvas。

既然Canvas主要用于绘图,那么它提供了很多相应的draw方法,方便我们在Canvas对象上绘图,介绍几个常用的draw方法:

voID drawRect(RectF rect,Paint paint) : 绘制区域,参数为RectF的区域。
voID drawoval(RectF oval,Paint paint) : 绘制矩形的内切椭圆。
voID drawCircle(float cx,float cy,float radius,Paint paint) : 绘制圆形。cx和cy是圆心坐标,radius是半径长度。
voID drawArc(RectF oval,float startAngle,float sweepAngle. boolean useCenter,Paint paint) : 绘制圆弧形,也是以矩形的内切椭圆为标准。其中,startAngle为起始角度,sweepAngle为弧度大小,useCenter为true,则是绘制一个扇行,为false,则只是一段圆弧。(ps:startAngle为0时,是圆形钟表3点钟方向)。
voID drawPath(Path path,Paint paint) : 根据给定的path,绘制连线。
voID drawBitmap(Bitmap bitmap,Rect src,Rect dst,Paint paint) : 贴图,参数bitmap是要进行绘制的bitmap对象,参数src是指bitmap的源区域(一般为null),dst是bitmap的目标区域,paint是画笔,可为null。
voID drawline(float startX,float startY,float stopX,float stopY,Paint paint) : 根据给定的起点和结束点之间绘制连线。
voID drawPoint(float x,float y,Paint paint) : 根据给定的坐标,绘制点。
voID drawText(String text,float x,Paint paint) : 根据给定的坐标,绘制文字。其中,x是文本起始的x轴坐标,y是文本纵向结束的y轴坐标。

画笔Paint

从上面列举的几个Canvas.drawXXX()方法可以看到,其中都有一个类型为Paint的参数,可以把它理解成为”画笔”,通过这个画笔,在Canvas这张画布上作画。它位于“androID.graphics.Paint”包下,主要用于设置绘图风格,包括画笔颜色。

Paint中提供了大量设置绘画风格的方法,这里仅列出一些常用的功能:

setARGB(int a,int r,int g,int b) : 设置ARGB颜色。
setcolor(int color) : 设置颜色。
setAlpha(int a) : 设置透明度。
setAntiAlias(boolean aa) : 设置是否抗锯齿。
setShader(Shader shader) : 设置Paint的填充效果。
setstrokeWIDth(float wIDth) : 设置Paint的笔触宽度。
setStyle(Paint.Style style) : 设置Paint的填充风格。
setTextSize(float textSize) : 设置绘制文本时的文字大小。

自定义圆形进度条

这里以一个自定义的圆形进度条为例,我们首先看一下效果图:

通过效果图,我们首先抽象出自定义属性,如下:

圆环内部填充色。
圆环进度条的背景色。
圆环进度条的颜色。
圆环半径。
圆环进度条的宽度。
进度条起始的角度。
中间文字的颜色。
中间文字的大小。
中间文字是否需要显示的标志位。

在AndroID中,可以在项目的res/values/目录下,建立一个resources源文件,通过declare-styleable来声明一个特定的属性集合。

示例属性集合如下所示(res/values/attrs_round_progress_bar.xml):

<resources>  <declare-styleable name="RoundProgressbar">    <attr name="startAngle" format="integer"></attr>    <attr name="radius" format="dimension"></attr>    <attr name="ringWIDth" format="dimension"></attr>    <attr name="centercolor" format="color"></attr>    <attr name="ringcolor" format="color"></attr>    <attr name="progresscolor" format="color"></attr>    <attr name="textSize" format="dimension"></attr>    <attr name="textcolor" format="color"></attr>    <attr name="isTextdisplay" format="boolean"></attr>  </declare-styleable></resources>

自定义的属性可以在自定义view的构造函数中,通过TypedArray数组获取,我们来自定义一个圆形的VIEw来实现上图的效果(RoundProgressbar.java):

package love.com.progressbar.vIEw;import androID.content.Context;import androID.content.res.TypedArray;import androID.graphics.Canvas;import androID.graphics.color;import androID.graphics.Paint;import androID.graphics.RectF;import androID.graphics.Typeface;import androID.util.AttributeSet;import androID.util.TypedValue;import androID.vIEw.VIEw;import love.com.progressbar.R;public class RoundProgressbar extends VIEw {  private static final int START_ANGLE = -90;  private static final String CENTER_color = "#eeff06";  private static final String RING_color = "#FF7281E1";  private static final String PROGRESS_color = "#FFDA0F0F";  private static final String TEXT_color = "#FF000000";  private static final int TEXT_SIZE = 30;  private static final int CIRCLE_RADIUS = 20;  private static final int RING_WIDTH = 5;  /**   * 圆弧的起始角度,参考canvas.drawArc方法   */  private int startAngle;  /**   * 圆形内半径   */  private int radius;  /**   * 进度条的宽度   */  private int ringWIDth;  /**   * 默认进度   */  private int mProgress = 0;  /**   * 圆形内部填充色   */  private int centercolor;  /**   * 进度条背景色   */  private int ringcolor;  /**   * 进度条的颜色   */  private int progresscolor;  /**   * 文字大小   */  private int textSize;  /**   * 文字颜色   */  private int textcolor;  /**   * 文字是否需要显示   */  private boolean isTextdisplay;  private String textContent;  private Paint mPaint;  public RoundProgressbar(Context context) {    this(context,null);  }  public RoundProgressbar(Context context,AttributeSet attrs) {    this(context,attrs,0);  }  public RoundProgressbar(Context context,AttributeSet attrs,int defStyle) {    super(context,defStyle);    // 获取自定义属性    TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RoundProgressbar);    for (int i = 0; i < a.length(); i ++) {      int attr = a.getIndex(i);      switch (attr) {        case R.styleable.RoundProgressbar_startAngle:          startAngle = a.getInteger(attr,START_ANGLE);          break;        case R.styleable.RoundProgressbar_centercolor:          centercolor = a.getcolor(attr,color.parsecolor(CENTER_color));          break;        case R.styleable.RoundProgressbar_progresscolor:          progresscolor = a.getcolor(attr,color.parsecolor(PROGRESS_color));          break;        case R.styleable.RoundProgressbar_ringcolor:          ringcolor = a.getcolor(attr,color.parsecolor(RING_color));          break;        case R.styleable.RoundProgressbar_textcolor:          textcolor = a.getcolor(attr,color.parsecolor(TEXT_color));          break;        case R.styleable.RoundProgressbar_textSize:          textSize = (int) a.getDimension(attr,TypedValue.applyDimension(              TypedValue.COMPLEX_UNIT_SP,TEXT_SIZE,getResources().getdisplayMetrics()));          break;        case R.styleable.RoundProgressbar_isTextdisplay:          isTextdisplay = a.getBoolean(attr,true);          break;        case R.styleable.RoundProgressbar_radius:          radius = (int) a.getDimension(attr,TypedValue.applyDimension(              TypedValue.COMPLEX_UNIT_DIP,CIRCLE_RADIUS,getResources().getdisplayMetrics()          ));          break;        case R.styleable.RoundProgressbar_ringWIDth:           ringWIDth = (int) a.getDimension(attr,RING_WIDTH,getResources().getdisplayMetrics()          ));          break;        default:          break;      }    }    a.recycle();    // 初始化画笔设置    setPaint();  }  private voID setPaint() {    mPaint = new Paint();    mPaint.setAntiAlias(true);  }  @OverrIDe  protected voID onDraw(Canvas canvas) {    super.onDraw(canvas);    // 获取圆心坐标    int cx = getWIDth() / 2;    int cy = cx;    /**     * 画圆心颜色     */    if (centercolor != 0) {      drawCenterCircle(canvas,cx,cy);    }    /**     * 画外层大圆     */    drawOuterCircle(canvas,cy);    /**     * 画进度圆弧     */    drawProgress(canvas,cy);    /**     * 画出进度百分比     */    drawProgresstext(canvas,cy);  }  private voID drawProgresstext(Canvas canvas,int cx,int cy) {    if (!isTextdisplay) {      return;    }    mPaint.setcolor(textcolor);    mPaint.setTextSize(textSize);    mPaint.setTypeface(Typeface.DEFAulT_BolD);    mPaint.setstrokeWIDth(0);    textContent = getProgress() + "%";    float textWIDth = mPaint.measureText(textContent);    canvas.drawText(textContent,cx - textWIDth / 2,cy + textSize / 2,mPaint);  }  private voID drawProgress(Canvas canvas,int cy) {    mPaint.setcolor(progresscolor);    mPaint.setstrokeWIDth(ringWIDth);    mPaint.setStyle(Paint.Style.stroke);    RectF mRectF = new RectF(cx - radius,cy - radius,cx + radius,cy + radius);    float sweepAngle = (float) (mProgress * 360.0 / 100);    canvas.drawArc(mRectF,startAngle,sweepAngle,false,mPaint);  }  private voID drawOuterCircle(Canvas canvas,int cy) {    mPaint.setStyle(Paint.Style.stroke);    mPaint.setcolor(ringcolor);    mPaint.setstrokeWIDth(ringWIDth);    canvas.drawCircle(cx,cy,radius,mPaint);  }  private voID drawCenterCircle(Canvas canvas,int cy) {    mPaint.setcolor(centercolor);    mPaint.setStyle(Paint.Style.FILL);    canvas.drawCircle(cx,mPaint);  }  public synchronized int getProgress() {    return mProgress;  }  public synchronized voID setProgress(int progress) {    if (progress < 0) {      progress = 0;    } else if (progress > 100) {      progress = 100;    }    mProgress = progress;    // 进度改变时,需要通过invalIDate方法进行重绘    postInvalIDate();  }}

在MainActivity.java的布局文件中,可以这样调用圆形进度条:

<?xml version="1.0" enCoding="utf-8"?><relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  xmlns:round="http://schemas.androID.com/apk/res-auto"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent">  <love.com.progressbar.vIEw.RoundProgressbar    androID:ID="@+ID/ID_round_progressbar"    androID:layout_wIDth="400dp"    androID:layout_height="400dp"    round:radius="100dp"    round:ringWIDth="20dp"    round:startAngle="-90"    round:centercolor="#eeff06"    round:ringcolor="#e16556e6"    round:progresscolor="#d20c0c"    round:textcolor="#000000"    round:textSize="20sp"    round:isTextdisplay="true"/></relativeLayout>

其中,xmlns:round=”http://schemas.androID.com/apk/res-auto是AndroID Studio中增加的导入自定义view属性的命名空间写法。

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

总结

以上是内存溢出为你收集整理的Android使用Canvas绘制圆形进度条效果全部内容,希望文章能够帮你解决Android使用Canvas绘制圆形进度条效果所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1141520.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存