Android自定义View实现圆弧进度效果
前言:android开发中,自定义view实现自己想要的效果已成为一项必备的技能,当然自定义view也是android开发中比较难的部分,涉及到的知识有canvas(画布),paint(画笔)等,自定义控件分为三种:一是直接继承自view,完全的自定义;二是在原有控件的基础上进行改造,达到自己想要的效果;还有一种就是自定义组合控件,将已有的控件根据自己的需要进行组合实现的效果。本人对自定义view也是一知半解,简单记录下自己学习自定义view(继承自view)的过程,方便日后翻阅。
技术实现
1.arcview继承自view
2.canvas(画布)
3.paint(画笔)
效果图:类似于qq的计步效果
1.继承自view
(1)重写3个构造方法(新的api中的构造方法是4个)
public arcview(context context) { this(context,null); } public arcview(context context, @nullable attributeset attrs) { this(context, attrs,0); } public arcview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); //init(); }
(2)重写view的ondraw方法
@suppresslint("drawallocation") @override protected void ondraw(canvas canvas) { super.ondraw(canvas); centerx=getwidth()/2; centery=getheight()/2; //初始化paint initpaint(); //绘制弧度 drawarc(canvas); //绘制文本 drawtext(canvas); }
注:这里的paint初始化我放在了ondraw方法中进行的,当然你也可以放在有三个参数的构造方法中初始化。
2.paint初始化
(1)圆弧的画笔marcpaint
//圆弧的paint marcpaint=new paint(paint.anti_alias_flag); //抗锯齿 marcpaint.setantialias(true); marcpaint.setcolor(color.parsecolor("#666666")); //设置透明度(数值为0-255) marcpaint.setalpha(100); //设置画笔的画出的形状 marcpaint.setstrokejoin(paint.join.round); marcpaint.setstrokecap(paint.cap.round); //设置画笔类型 marcpaint.setstyle(paint.style.stroke); marcpaint.setstrokewidth(dp2px(mstrokewith));
(2)文字的画笔mtextpaint
//中心文字的paint mtextpaint=new paint(); mtextpaint.setantialias(true); mtextpaint.setcolor(color.parsecolor("#ff4a40")); //设置文本的对齐方式 mtextpaint.settextalign(paint.align.center); //mtextpaint.settextsize(getresources().getdimensionpixelsize(r.dimen.dp_12)); mtextpaint.settextsize(dp2px(25));
3.canvas绘制
(1)圆弧的绘制
/** * 绘制圆弧 * @param canvas */ private void drawarc(canvas canvas) { //绘制圆弧背景 rectf mrectf=new rectf(mstrokewith+dp2px(5),mstrokewith+dp2px(5),getwidth()-mstrokewith-dp2px(5),getheight()-mstrokewith); canvas.drawarc(mrectf,startangle,mangle,false,marcpaint); //绘制当前数值对应的圆弧 marcpaint.setcolor(color.parsecolor("#ff4a40")); //根据当前数据绘制对应的圆弧 canvas.drawarc(mrectf,startangle,mincludedangle,false,marcpaint); }
(2)文本的绘制
/** * 绘制文本 * @param canvas */ private void drawtext(canvas canvas) { rect mrect=new rect(); string mvalue=string.valueof(manimatorvalue); //绘制中心的数值 mtextpaint.gettextbounds(mvalue,0,mvalue.length(),mrect); canvas.drawtext(string.valueof(manimatorvalue),centerx,centery+mrect.height(),mtextpaint); //绘制中心文字描述 mtextpaint.setcolor(color.parsecolor("#999999")); mtextpaint.settextsize(dp2px(12)); mtextpaint.gettextbounds(mdes,0,mdes.length(),mrect); canvas.drawtext(mdes,centerx,centery+2*mrect.height()+dp2px(10),mtextpaint); //绘制最小值 string minvalue=string.valueof(mminvalue); string maxvalue=string.valueof(mmaxvalue); mtextpaint.settextsize(dp2px(18)); mtextpaint.gettextbounds(minvalue,0,minvalue.length(),mrect); canvas.drawtext(minvalue, (float) (centerx-0.6*centerx-dp2px(5)), (float) (centery+0.75*centery+mrect.height()+dp2px(5)),mtextpaint); //绘制最大值 mtextpaint.gettextbounds(maxvalue,0,maxvalue.length(),mrect); canvas.drawtext(maxvalue, (float) (centerx+0.6*centerx+dp2px(5)), (float) (centery+0.75*centery+mrect.height()+dp2px(5)),mtextpaint); }
4.添加动画效果及数据
(1)动画效果
/** * 为绘制弧度及数据设置动画 * * @param startangle 开始的弧度 * @param currentangle 需要绘制的弧度 * @param currentvalue 需要绘制的数据 * @param time 动画执行的时长 */ private void setanimation(float startangle, float currentangle,int currentvalue, int time) { //绘制当前数据对应的圆弧的动画效果 valueanimator progressanimator = valueanimator.offloat(startangle, currentangle); progressanimator.setduration(time); progressanimator.settarget(mincludedangle); progressanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { mincludedangle = (float) animation.getanimatedvalue(); //重新绘制,不然不会出现效果 postinvalidate(); } }); //开始执行动画 progressanimator.start(); //中心数据的动画效果 valueanimator valueanimator = valueanimator.ofint(manimatorvalue, currentvalue); valueanimator.setduration(2500); valueanimator.setinterpolator(new linearinterpolator()); valueanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator valueanimator) { manimatorvalue = (int) valueanimator.getanimatedvalue(); postinvalidate(); } }); valueanimator.start(); }
(2)数据添加
/** * 设置数据 * @param minvalue 最小值 * @param maxvalue 最大值 * @param currentvalue 当前绘制的值 * @param des 描述信息 */ public void setvalues(int minvalue,int maxvalue, int currentvalue,string des) { mdes=des; mmaxvalue=maxvalue; mminvalue=minvalue; //完全覆盖背景弧度 if (currentvalue > maxvalue) { currentvalue = maxvalue; } //计算弧度比重 float scale = (float) currentvalue / maxvalue; //计算弧度 float currentangle = scale * mangle; //开始执行动画 setanimation(0, currentangle, currentvalue,2500);
完整代码:
/** * created by ruancw on 2018/6/13. * 自定义的圆弧形view */ public class arcview extends view { //根据数据显示的圆弧paint private paint marcpaint; //文字描述的paint private paint mtextpaint; //圆弧开始的角度 private float startangle=135; //圆弧结束的角度 private float endangle=45; //圆弧背景的开始和结束间的夹角大小 private float mangle=270; //当前进度夹角大小 private float mincludedangle=0; //圆弧的画笔的宽度 private float mstrokewith=10; //中心的文字描述 private string mdes=""; //动画效果的数据及最大/小值 private int manimatorvalue,mminvalue,mmaxvalue; //中心点的xy坐标 private float centerx,centery; public arcview(context context) { this(context,null); } public arcview(context context, @nullable attributeset attrs) { this(context, attrs,0); } public arcview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); //init(); } private void initpaint() { //圆弧的paint marcpaint=new paint(paint.anti_alias_flag); //抗锯齿 marcpaint.setantialias(true); marcpaint.setcolor(color.parsecolor("#666666")); //设置透明度(数值为0-255) marcpaint.setalpha(100); //设置画笔的画出的形状 marcpaint.setstrokejoin(paint.join.round); marcpaint.setstrokecap(paint.cap.round); //设置画笔类型 marcpaint.setstyle(paint.style.stroke); marcpaint.setstrokewidth(dp2px(mstrokewith)); //中心文字的paint mtextpaint=new paint(); mtextpaint.setantialias(true); mtextpaint.setcolor(color.parsecolor("#ff4a40")); //设置文本的对齐方式 mtextpaint.settextalign(paint.align.center); //mtextpaint.settextsize(getresources().getdimensionpixelsize(r.dimen.dp_12)); mtextpaint.settextsize(dp2px(25)); } @suppresslint("drawallocation") @override protected void ondraw(canvas canvas) { super.ondraw(canvas); centerx=getwidth()/2; centery=getheight()/2; //初始化paint initpaint(); //绘制弧度 drawarc(canvas); //绘制文本 drawtext(canvas); } /** * 绘制文本 * @param canvas */ private void drawtext(canvas canvas) { rect mrect=new rect(); string mvalue=string.valueof(manimatorvalue); //绘制中心的数值 mtextpaint.gettextbounds(mvalue,0,mvalue.length(),mrect); canvas.drawtext(string.valueof(manimatorvalue),centerx,centery+mrect.height(),mtextpaint); //绘制中心文字描述 mtextpaint.setcolor(color.parsecolor("#999999")); mtextpaint.settextsize(dp2px(12)); mtextpaint.gettextbounds(mdes,0,mdes.length(),mrect); canvas.drawtext(mdes,centerx,centery+2*mrect.height()+dp2px(10),mtextpaint); //绘制最小值 string minvalue=string.valueof(mminvalue); string maxvalue=string.valueof(mmaxvalue); mtextpaint.settextsize(dp2px(18)); mtextpaint.gettextbounds(minvalue,0,minvalue.length(),mrect); canvas.drawtext(minvalue, (float) (centerx-0.6*centerx-dp2px(5)), (float) (centery+0.75*centery+mrect.height()+dp2px(5)),mtextpaint); //绘制最大指 mtextpaint.gettextbounds(maxvalue,0,maxvalue.length(),mrect); canvas.drawtext(maxvalue, (float) (centerx+0.6*centerx+dp2px(5)), (float) (centery+0.75*centery+mrect.height()+dp2px(5)),mtextpaint); } /** * 绘制当前的圆弧 * @param canvas */ private void drawarc(canvas canvas) { //绘制圆弧背景 rectf mrectf=new rectf(mstrokewith+dp2px(5),mstrokewith+dp2px(5),getwidth()-mstrokewith-dp2px(5),getheight()-mstrokewith); canvas.drawarc(mrectf,startangle,mangle,false,marcpaint); //绘制当前数值对应的圆弧 marcpaint.setcolor(color.parsecolor("#ff4a40")); //根据当前数据绘制对应的圆弧 canvas.drawarc(mrectf,startangle,mincludedangle,false,marcpaint); } /** * 为绘制弧度及数据设置动画 * * @param startangle 开始的弧度 * @param currentangle 需要绘制的弧度 * @param currentvalue 需要绘制的数据 * @param time 动画执行的时长 */ private void setanimation(float startangle, float currentangle,int currentvalue, int time) { //绘制当前数据对应的圆弧的动画效果 valueanimator progressanimator = valueanimator.offloat(startangle, currentangle); progressanimator.setduration(time); progressanimator.settarget(mincludedangle); progressanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { mincludedangle = (float) animation.getanimatedvalue(); //重新绘制,不然不会出现效果 postinvalidate(); } }); //开始执行动画 progressanimator.start(); //中心数据的动画效果 valueanimator valueanimator = valueanimator.ofint(manimatorvalue, currentvalue); valueanimator.setduration(2500); valueanimator.setinterpolator(new linearinterpolator()); valueanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator valueanimator) { manimatorvalue = (int) valueanimator.getanimatedvalue(); postinvalidate(); } }); valueanimator.start(); } /** * 设置数据 * @param minvalue 最小值 * @param maxvalue 最大值 * @param currentvalue 当前绘制的值 * @param des 描述信息 */ public void setvalues(int minvalue,int maxvalue, int currentvalue,string des) { mdes=des; mmaxvalue=maxvalue; mminvalue=minvalue; //完全覆盖 if (currentvalue > maxvalue) { currentvalue = maxvalue; } //计算弧度比重 float scale = (float) currentvalue / maxvalue; //计算弧度 float currentangle = scale * mangle; //开始执行动画 setanimation(0, currentangle, currentvalue,2500); } public float dp2px(float dp) { displaymetrics metrics = resources.getsystem().getdisplaymetrics(); return dp * metrics.density; } }
总结:设置paint的画笔形状(cap和join设置为弧形);使用canvas的drawarc方法绘制圆弧及drawtext绘制文本信息等;valueanimator设置数据及当前圆弧进度的动画效果。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 炝拌莴苣的炝是什么意思
下一篇: 长期喝奶茶致癌吗