Android实现渐变圆环、圆形进度条效果
最近做了一个功能,里面涉及到了渐变圆形的需求。就是一个颜色可以渐变的圆环,最后实现的效果如下图:
左图是带渐变效果,右图是不带渐变效果。原理还是绘图,canvas可以绘制的对象有:弧线(arcs)、填充颜色(argb和color)、 bitmap、圆(circle和oval)、点(point)、线(line)、矩形(rect)、图片(picture)、圆角矩形 (roundrect)、文本(text)、顶点(vertices)、路径(path)。通过组合这些对象我们可以画出一些简单有趣的界面出来,但是光有这些功能还是不够的,如果我要画一个仪表盘(数字围绕显示在一个圆圈中)呢? 幸好android还提供了一些对canvas位置转换的方法:rorate、scale、translate、skew(扭曲)等,而且它允许你通过获得它的转换矩阵对象(getmatrix方法,不知道什么是转换矩阵?) 直接操作它。这些操作就像是虽然你的笔还是原来的地方画,但是画纸旋转或者移动了,所以你画的东西的方位就产生变化。为了方便一些转换操作,canvas 还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。
话不多说,上代码
核心类:
自定义控件 circleprogressbar
package com.jky.mobile_xmxt.view; import android.content.context; import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.graphics.rectf; import android.graphics.sweepgradient; import android.util.attributeset; import android.view.view; import android.view.animation.animation; import android.view.animation.transformation; import com.jky.mobile_xmxt.r; import java.text.decimalformat; /** * 圆盘计步图表 */ public class circleprogressbar extends view { private rectf mwheelrect = new rectf(); private paint mdefaultwheelpaint; private paint mfinishwheelpaint; private paint mcenterwheelpaint; private paint mtitlepaint, msteppaint, mtargetpaint; private float mcirclestrokewidth; private float msweepangleper; private float mpercent; private int mstepnum, mcurrstepnum; private float pressextrastrokewidth; private baranimation manim; private int mmaxstepnum;// 默认最大步数 private float mtitley, mstepy, mtargety; private decimalformat mdecimalformat = new decimalformat("#.0");// 格式为保留小数点后一位 public static string goal_step; public static string percent; public circleprogressbar(context context) { super(context); init(null, 0); } public circleprogressbar(context context, attributeset attrs) { super(context, attrs); init(attrs, 0); } public circleprogressbar(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(attrs, defstyle); } private void init(attributeset attrs, int defstyle) { mfinishwheelpaint = new paint(); mfinishwheelpaint.setcolor(color.rgb(100, 113, 205)); mfinishwheelpaint.setstyle(paint.style.stroke);// 空心 mfinishwheelpaint.setstrokecap(paint.cap.round);// 圆角画笔 mfinishwheelpaint.setantialias(true);// 去锯齿 mcenterwheelpaint = new paint(); mcenterwheelpaint.setcolor(color.rgb(243, 243, 243)); mcenterwheelpaint.setstyle(paint.style.stroke); mcenterwheelpaint.setstrokecap(paint.cap.round); mcenterwheelpaint.setantialias(true); mdefaultwheelpaint = new paint(); mdefaultwheelpaint.setcolor(color.rgb(127, 127, 127)); mdefaultwheelpaint.setstyle(paint.style.stroke); mdefaultwheelpaint.setstrokecap(paint.cap.round); mdefaultwheelpaint.setantialias(true); mtitlepaint = new paint(); mtitlepaint.setantialias(true); mtitlepaint.setcolor(color.white); msteppaint = new paint(); msteppaint.setantialias(true); msteppaint.setcolor(color.white); mtargetpaint = new paint(); mtargetpaint.setantialias(true); mtargetpaint.setcolor(color.white); manim = new baranimation(); } @override protected void ondraw(canvas canvas) { canvas.drawarc(mwheelrect, 0, 359, false, mdefaultwheelpaint); canvas.drawarc(mwheelrect, 0, 359, false, mcenterwheelpaint); canvas.drawarc(mwheelrect, 90, msweepangleper, false, mfinishwheelpaint); // canvas.drawtext("步数", mwheelrect.centerx() - (mtitlepaint.measuretext("步数") / 2), mtitley, // mtitlepaint); canvas.drawtext(mcurrstepnum + "", mwheelrect.centerx() - (msteppaint.measuretext(string.valueof(mcurrstepnum)) / 2), mstepy, msteppaint); string description = ""; float percent = getpercent(); if(percent > 0.5){ description ="严重污染"; }else if(percent<0.5){ description ="中等污染"; }else{ description ="普通污染"; } canvas.drawtext(description , mwheelrect.centerx() - (mtargetpaint.measuretext(description) / 2), mtargety, mtargetpaint); sweepgradient sweepgradient = new sweepgradient(mwheelrect.centerx(), mwheelrect.centery(), new int[]{getresources().getcolor(r.color.color_environment_severe), getresources().getcolor(r.color.color_environment_serious), getresources().getcolor(r.color.color_environment_excellent), getresources().getcolor(r.color.color_environment_good), getresources().getcolor(r.color.color_environment_mild), getresources().getcolor(r.color.color_environment_moderate)}, null); mfinishwheelpaint.setshader(sweepgradient); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int height = getdefaultsize(getsuggestedminimumheight(), heightmeasurespec); int width = getdefaultsize(getsuggestedminimumwidth(), widthmeasurespec); int min = math.min(width, height);// 获取view最短边的长度 setmeasureddimension(min, min);// 强制改view为以最短边为长度的正方形 mcirclestrokewidth = gettextscale(15, min);// 圆弧的宽度 pressextrastrokewidth = gettextscale(10, min);// 圆弧离矩形的距离 mwheelrect.set(mcirclestrokewidth + pressextrastrokewidth, mcirclestrokewidth + pressextrastrokewidth, min - mcirclestrokewidth - pressextrastrokewidth, min - mcirclestrokewidth - pressextrastrokewidth);// 设置矩形 mtitlepaint.settextsize(gettextscale(60, min)); msteppaint.settextsize(gettextscale(120, min)); mtargetpaint.settextsize(gettextscale(40, min)); mtitley = gettextscale(170, min); mstepy = gettextscale(300, min); mtargety = gettextscale(380, min); mfinishwheelpaint.setstrokewidth(mcirclestrokewidth); mcenterwheelpaint.setstrokewidth(mcirclestrokewidth); mdefaultwheelpaint.setstrokewidth(mcirclestrokewidth - gettextscale(2, min)); mdefaultwheelpaint.setshadowlayer(gettextscale(10, min), 0, 0, color.rgb(127, 127, 127));// 设置阴影 } /** * 进度条动画 * * @author administrator */ public class baranimation extends animation { /** * 每次系统调用这个方法时, 改变msweepangleper,mpercent,stepnumbernow的值, * 然后调用postinvalidate()不停的绘制view。 */ @override protected void applytransformation(float interpolatedtime, transformation t) { // if (interpolatedtime < 1.0f) { // mpercent = float.parsefloat(mdecimalformat.format(interpolatedtime * mstepnum * 100f / mmaxstepnum));// 将浮点值四舍五入保留一位小数 // msweepangleper = interpolatedtime * mstepnum * 360 / mmaxstepnum; // mcurrstepnum = (int) (interpolatedtime * mstepnum); // } else { mpercent = float.parsefloat(mdecimalformat.format(mstepnum * 100f / mmaxstepnum));// 将浮点值四舍五入保留一位小数 if (mpercent > 100.0f) { mpercent = 100.0f; } percent = string.valueof(mpercent); msweepangleper = mstepnum * 360 / mmaxstepnum; mcurrstepnum = mstepnum; // } requestlayout(); } } public float getpercent() { return mpercent; } /** * 根据控件的大小改变绝对位置的比例 * * @param n * @param m * @return */ public float gettextscale(float n, float m) { return n / 500 * m; } /** * 更新步数和设置一圈动画时间 * * @param stepcount * @param time */ public void update(int stepcount, int time) { this.mstepnum = stepcount; manim.setduration(time); // setanimationtime(time); this.startanimation(manim); } /** * @param stepnum */ public void setmaxstepnum(int stepnum) { mmaxstepnum = stepnum; goal_step = string.valueof(mmaxstepnum); } public void setcolor(int color) { mfinishwheelpaint.setcolor(color); msteppaint.setcolor(color); } /** * 设置动画时间 * * @param time */ public void setanimationtime(int time) { manim.setduration(time * mstepnum / mmaxstepnum);// 按照比例设置动画执行时间 } }
xml引用
<com.jky.mobile_xmxt.view.circleprogressbar android:id="@+id/color_progress_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="6" />
activity调用方法
color_progress_view = (circleprogressbar)view.findviewbyid(r.id.color_progress_view); color_progress_view.setmaxstepnum(500); color_progress_view.update(470,1000);
由于和调用其他控件方法类似,姑且省去了很多其他业务逻辑代码,代码不是特别复杂,修改起来也很方便(修改颜色,总量及比例等),所以只粘贴核心相关的代码,希望可以帮助到大家。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Android实现静态广播监听器的方法
下一篇: 3张图片循环组和(很有动感)