Android自定义控件之圆形进度条动画
程序员文章站
2022-04-25 20:28:25
本文实例为大家分享了android实现圆形进度条动画的具体代码,供大家参考,具体内容如下首先贴上图片:额,感觉还行吧,就是进度条的颜色丑了点,不过咱是程序员,不是美工,配色这种问题当然不在考虑范围之内...
本文实例为大家分享了android实现圆形进度条动画的具体代码,供大家参考,具体内容如下
首先贴上图片:
额,感觉还行吧,就是进度条的颜色丑了点,不过咱是程序员,不是美工,配色这种问题当然不在考虑范围之内了。
下面说重点,如何来写一个这样的自定义控件。
首先,需要有一个灰色的底图,来作为未填充时的进度条;
然后,根据传入的当前进度值,绘制填充时的进度圆弧,这段圆弧所对应的圆心角,由当前进度与进度的最大值(一般是100)的比值计算得出;
其次,根据进度值绘制文字提示;
最后,重绘控件,加上动画,从而达到显示进度的效果。
代码如下:
1、attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="circleprogressbar"> <attr name="circlewidth" format="dimension" /> <attr name="betaangle" format="integer" /> <attr name="firstcolor" format="color" /> <attr name="secondcolor" format="color" /> </declare-styleable> </resources>
2、circleprogressbar.java
package com.ctgu.circleprogressbar; import android.animation.valueanimator; import android.content.context; import android.content.res.typedarray; import android.graphics.canvas; import android.graphics.color; import android.graphics.lineargradient; import android.graphics.paint; import android.graphics.paint.fontmetricsint; import android.graphics.rect; import android.graphics.rectf; import android.graphics.shader; import android.util.attributeset; import android.util.typedvalue; import android.view.view; import android.view.animation.overshootinterpolator; public class circleprogressbar extends view { /** * 进度条最大值,默认为100 */ private int maxvalue = 100; /** * 当前进度值 */ private int currentvalue = 0; /** * 每次扫过的角度,用来设置进度条圆弧所对应的圆心角,alphaangle=(currentvalue/maxvalue)*360 */ private float alphaangle; /** * 底部圆弧的颜色,默认为color.ltgray */ private int firstcolor; /** * 进度条圆弧块的颜色 */ private int secondcolor; /** * 圆环的宽度 */ private int circlewidth; /** * 画圆弧的画笔 */ private paint circlepaint; /** * 画文字的画笔 */ private paint textpaint; /** * 渐变圆周颜色数组 */ private int[] colorarray = new int[] { color.parsecolor("#27b197"), color.parsecolor("#00a6d5") };// /** * 通过代码创建时才使用 * * @param context */ public circleprogressbar(context context) { this(context, null); } /** * 当从xml中加载view的时候,这个构造器才会被调用。其第二个参数中就包含自定义的属性。 * * @param context * 上下文 * @param attrs * 自定义属性 */ public circleprogressbar(context context, attributeset attrs) { this(context, attrs, 0); } /** * 从xml加载时执行和应用一个特定的风格。这里有两种方式,一是从theme中获得,二是从style中获得。 * 第三个参数官方有这样的说明: defstyle - the default style to apply to this view. if 0, * no style will be applied (beyond what is included in the theme). this may * either be an attribute resource, whose value will be retrieved from the * current theme, or an explicit style resource. * 默认的风格会被应用到这个view上。如果是0,没有风格将会被应用 * (除了被包含在主题中)。这个也许是一个属性的资源,它的值是从当前的主题中检索,或者是一个明确的风格资源。 * * @param context * 上下文 * @param attrs * 自定义的属性 * @param defstyleattr * 自定义风格 */ public circleprogressbar(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); typedarray ta = context.gettheme().obtainstyledattributes(attrs, r.styleable.circleprogressbar, defstyleattr, 0); int n = ta.getindexcount(); for (int i = 0; i < n; i++) { int attr = ta.getindex(i); switch (attr) { case r.styleable.circleprogressbar_firstcolor: firstcolor = ta.getcolor(attr, color.ltgray); // 默认底色为亮灰色 break; case r.styleable.circleprogressbar_secondcolor: secondcolor = ta.getcolor(attr, color.blue); // 默认进度条颜色为蓝色 break; case r.styleable.circleprogressbar_circlewidth: circlewidth = ta.getdimensionpixelsize(attr, (int) typedvalue.applydimension( typedvalue.complex_unit_dip, 6, getresources().getdisplaymetrics())); // 默认圆弧宽度为6dp break; default: break; } } ta.recycle(); circlepaint = new paint(); circlepaint.setantialias(true); // 抗锯齿 circlepaint.setdither(true); // 防抖动 circlepaint.setstrokewidth(circlewidth); textpaint = new paint(); textpaint.setantialias(true); textpaint.setdither(true); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {// 分别获取期望的宽度和高度,并取其中较小的尺寸作为该控件的宽和高 int measurewidth = measurespec.getsize(widthmeasurespec); int measureheight = measurespec.getsize(heightmeasurespec); setmeasureddimension(math.min(measurewidth, measureheight), math.min(measurewidth, measureheight)); } @override protected void ondraw(canvas canvas) { int center = this.getwidth() / 2; int radius = center - circlewidth / 2; drawcircle(canvas, center, radius); // 绘制进度圆弧 drawtext(canvas, center, radius); } /** * 绘制进度圆弧 * * @param canvas * 画布对象 * @param center * 圆心的x和y坐标 * @param radius * 圆的半径 */ private void drawcircle(canvas canvas, int center, int radius) { circlepaint.setshader(null); // 清除上一次的shader circlepaint.setcolor(firstcolor); // 设置底部圆环的颜色,这里使用第一种颜色 circlepaint.setstyle(paint.style.stroke); // 设置绘制的圆为空心 canvas.drawcircle(center, center, radius, circlepaint); // 画底部的空心圆 rectf oval = new rectf(center - radius, center - radius, center + radius, center + radius); // 圆的外接正方形 // 绘制颜色渐变圆环 // shader类是android在图形变换中非常重要的一个类。shader在三维软件中我们称之为着色器,其作用是来给图像着色。 lineargradient lineargradient = new lineargradient(circlewidth, circlewidth, getmeasuredwidth() - circlewidth, getmeasuredheight() - circlewidth, colorarray, null, shader.tilemode.mirror); circlepaint.setshader(lineargradient); circlepaint.setshadowlayer(10, 10, 10, color.red); circlepaint.setcolor(secondcolor); // 设置圆弧的颜色 circlepaint.setstrokecap(paint.cap.round); // 把每段圆弧改成圆角的 alphaangle = currentvalue * 360.0f / maxvalue * 1.0f; // 计算每次画圆弧时扫过的角度,这里计算要注意分母要转为float类型,否则alphaangle永远为0 canvas.drawarc(oval, -90, alphaangle, false, circlepaint); } /** * 绘制文字 * * @param canvas * 画布对象 * @param center * 圆心的x和y坐标 * @param radius * 圆的半径 */ private void drawtext(canvas canvas, int center, int radius) { float result = (currentvalue * 100.0f / maxvalue * 1.0f); // 计算进度 string percent = string.format("%.1f", result) + "%"; textpaint.settextalign(paint.align.center); // 设置文字居中,文字的x坐标要注意 textpaint.setcolor(color.black); // 设置文字颜色 textpaint.settextsize(40); // 设置要绘制的文字大小 textpaint.setstrokewidth(0); // 注意此处一定要重新设置宽度为0,否则绘制的文字会重叠 rect bounds = new rect(); // 文字边框 textpaint.gettextbounds(percent, 0, percent.length(), bounds); // 获得绘制文字的边界矩形 fontmetricsint fontmetrics = textpaint.getfontmetricsint(); // 获取绘制text时的四条线 int baseline = center + (fontmetrics.bottom - fontmetrics.top) / 2 - fontmetrics.bottom; // 计算文字的基线,方法见http://blog.csdn.net/harvic880925/article/details/50423762 canvas.drawtext(percent, center, baseline, textpaint); // 绘制表示进度的文字 } /** * 设置圆环的宽度 * * @param width */ public void setcirclewidth(int width) { this.circlewidth = (int) typedvalue.applydimension(typedvalue.complex_unit_dip, width, getresources() .getdisplaymetrics()); circlepaint.setstrokewidth(circlewidth); invalidate(); } /** * 设置圆环的底色,默认为亮灰色ltgray * * @param color */ public void setfirstcolor(int color) { this.firstcolor = color; circlepaint.setcolor(firstcolor); invalidate(); } /** * 设置进度条的颜色,默认为蓝色<br> * * @param color */ public void setsecondcolor(int color) { this.secondcolor = color; circlepaint.setcolor(secondcolor); invalidate(); } /** * 设置进度条渐变色颜色数组 * * @param colors * 颜色数组,类型为int[] */ public void setcolorarray(int[] colors) { this.colorarray = colors; invalidate(); } /** * 按进度显示百分比 * * @param progress * 进度,值通常为0到100 */ public void setprogress(int progress) { int percent = progress * maxvalue / 100; if (percent < 0) { percent = 0; } if (percent > 100) { percent = 100; } this.currentvalue = percent; invalidate(); } /** * 按进度显示百分比,可选择是否启用数字动画 * * @param progress * 进度,值通常为0到100 * @param useanimation * 是否启用动画,true为启用 */ public void setprogress(int progress, boolean useanimation) { int percent = progress * maxvalue / 100; if (percent < 0) { percent = 0; } if (percent > 100) { percent = 100; } if (useanimation) // 使用动画 { valueanimator animator = valueanimator.ofint(0, percent); animator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { currentvalue = (int) animation.getanimatedvalue(); invalidate(); } }); animator.setinterpolator(new overshootinterpolator()); animator.setduration(1000); animator.start(); } else { setprogress(progress); } } }
3、activity_main.xml
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:lh2="http://schemas.android.com/apk/res/com.ctgu.circleprogressbar" android:layout_width="match_parent" android:layout_height="match_parent" > <com.ctgu.circleprogressbar.circleprogressbar android:id="@+id/circleprogressbar" android:layout_width="150dp" android:layout_height="150dp" android:layout_centerhorizontal="true" android:layout_gravity="center" android:layout_margintop="20dp" lh2:circlewidth="6dp" lh2:firstcolor="#d3d3d3" lh2:secondcolor="#3b95c8" /> <seekbar android:id="@+id/seekbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignparentbottom="true" android:layout_marginbottom="40dp" android:layout_marginleft="10dp" android:layout_marginright="10dp" android:background="#778899" /> </relativelayout>
4、mainactivity.java
package com.ctgu.circleprogressbar; import android.app.activity; import android.graphics.color; import android.os.bundle; import android.os.handler; import android.widget.seekbar; public class mainactivity extends activity { private circleprogressbar circleprogressbar; // 自定义的进度条 private seekbar seekbar; // 拖动条 private int[] colors = new int[] { color.parsecolor("#27b197"), color.parsecolor("#00a6d5") }; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); circleprogressbar = (circleprogressbar) findviewbyid(r.id.circleprogressbar); // circleprogressbar.setfirstcolor(color.ltgray); // circleprogressbar.setcolorarray(colors); //觉得进度条颜色丑的,这里可以自行传入一个颜色渐变数组。 // circleprogressbar.setcirclewidth(6); seekbar = (seekbar) findviewbyid(r.id.seekbar); seekbar.setmax(100); seekbar.setonseekbarchangelistener(new seekbar.onseekbarchangelistener() { @override public void onstoptrackingtouch(seekbar seekbar) { } @override public void onstarttrackingtouch(seekbar seekbar) { } @override public void onprogresschanged(seekbar seekbar, int progress, boolean fromuser) { if (fromuser) { // circleprogressbar.setprogress(progress); //不使用动画 circleprogressbar.setprogress(progress, true); // 使用数字过渡动画 } } }); } }
代码注释很详细了,基本上了解自定义控件的都看得懂。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。