Android使用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, float y, 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, attrs, 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, TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 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, cx, cy); /** * 画进度圆弧 */ drawProgress(canvas, cx, cy); /** * 画出进度百分比 */ drawProgressText(canvas, cx, 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 cx, 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 cx, 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 cx, int cy) { mPaint.setColor(centerColor); mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(cx, cy, radius, 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属性的命名空间写法。

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

时间: 2024-08-02 14:29:44

Android使用Canvas绘制圆形进度条效果的相关文章

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

前言 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 B

Android(安卓) ClipDrawable 实现圆形进度条效果

话就不多说了,直接上代码. 二.源码 步骤一.在根目录下创建 drawable文件夹,然后在drawable里创建clip_btimap.xml  代码如下 复制代码 <?xml version="1.0" encoding="utf-8"?> <clip xmlns:android="http://schemas.android.com/apk/res/android"     android:clipOrientation=

Android自定义View之圆形进度条总结

最近撸了一个圆形进度条的开源项目,算是第一次完完整整的使用自定义 View .在此对项目开发思路做个小结,欢迎大家 Star 和 Fork. 该项目总共实现了三种圆形进度条效果 CircleProgress:圆形进度条,可以实现仿 QQ 健康计步器的效果,支持配置进度条背景色.宽度.起始角度,支持进度条渐变 DialProgress:类似 CircleProgress,但是支持刻度 WaveProgress:实现了水波纹效果的圆形进度条,不支持渐变和起始角度配置,如需此功能可参考 CircleP

Android自定义View之圆形进度条式按钮_Android

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

解决html5中canvas绘制圆环进度条出现模糊效果方案

问题 近期用canvas绘制了圆环进度条,但是进度条出现周围模糊的现象,针对这种现象,网上搜了搜,有人提问,但是貌似没有很好的解决方案,针对这种情况,提出几种解决方案,仅供参考! 模糊效果如下: 解决方案 针对这种情况,我提出几种解决思路. 一.运用hidpi-canvas-polyfill 的js进行解决 HiDPI Canvas Polyfill 是针对设备提出的canvas高清解决方案,首先引入hidpi-canvas.js. 这个js会自动识别你的canvas,会把你的canvas变小,

Android自定义View之圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

Android编程之ProgressBar圆形进度条颜色设置方法

本文实例讲述了Android ProgressBar圆形进度条颜色设置方法.分享给大家供大家参考,具体如下: 你是不是还在为设置进度条的颜色而烦恼呢--别着急,且看如下如何解决. ProgressBar分圆形进度条和水平进度条 我这里就分享下如何设置圆形进度条的颜色吧,希望对大家会有帮助. 源码如下: 布局文件代码: <ProgressBar android:id="@+id/progressbar" android:layout_width="wrap_content

Android 自定义漂亮的圆形进度条

这几天对Android中实现画圆弧及圆弧效果中所实现的效果进行了修改,改为进度圆心进度条,效果如图所示   TasksCompletedView.java 代码如下 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; im

Android自定义漂亮的圆形进度条

这几天对Android中实现画圆弧及圆弧效果中所实现的效果进行了修改,改为进度圆心进度条,效果如图所示 TasksCompletedView.java 代码如下 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; impo