QQ运动步数&自定义ProgressBar
程序员文章站
2022-08-08 09:55:56
效果如下 gif图展示效果不好,实际体验无卡顿 1.自定义属性 早Values目录下New values resource file,命名为attrs.xml(命名随意,但规范命名为attrs.xml) 自定义属性如下,注意format不要与Android自带的命名重复。 2.编写自定义View 3 ......
效果如下
gif图展示效果不好,实际体验无卡顿
1.自定义属性
早values目录下new-values resource file,命名为attrs.xml(命名随意,但规范命名为attrs.xml)
自定义属性如下,注意format不要与android自带的命名重复。
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="qqstepview"> <attr name="outercolor" format="color" /> <attr name="innercolor" format="color" /> <attr name="borderwidth" format="dimension" /> <attr name="steptextsize" format="dimension" /> <attr name="steptextcolor" format="color" /> </declare-styleable> <declare-styleable name="myprogressbar"> <attr name="leftcolor" format="color" /> <attr name="rightcolor" format="color" /> <attr name="progresstextcolor" format="color" /> <attr name="progresstextsize" format="dimension" /> <attr name="progressbounds" format="dimension" /> </declare-styleable> </resources>
2.编写自定义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.rect; import android.graphics.rectf; import android.support.annotation.nullable; import android.util.attributeset; import android.view.view; import com.cyq.customview2.r; import com.cyq.customview2.utils.measureutils; @suppresswarnings("all") public class qqstepview extends view { private int moutercolor = color.parsecolor("#2196f3"); private int minnercolor = color.parsecolor("#f44336"); private int msteptextcolor = color.parsecolor("#ec407a"); private int mborderwidth = 20;//px private int msteptextsize = 18;//px private int mseptmax = 10000; private int mseptcurrent = 0; private paint moutpaint; private paint minnerpaint; private paint mtextpaint; public qqstepview(context context) { this(context, null); } public qqstepview(context context, @nullable attributeset attrs) { this(context, attrs, 0); } public qqstepview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); typedarray array = context.obtainstyledattributes(attrs, r.styleable.qqstepview); moutercolor = array.getcolor(r.styleable.qqstepview_outercolor, moutercolor); minnercolor = array.getcolor(r.styleable.qqstepview_innercolor, minnercolor); msteptextcolor = array.getcolor(r.styleable.qqstepview_steptextcolor, msteptextcolor); mborderwidth = (int) array.getdimension(r.styleable.qqstepview_borderwidth, measureutils.dp2px(mborderwidth, this)); msteptextsize = array.getdimensionpixelsize(r.styleable.qqstepview_steptextsize, measureutils.sp2px(msteptextsize, this)); array.recycle(); moutpaint = new paint(); moutpaint.setantialias(true); moutpaint.setstrokewidth(mborderwidth); moutpaint.setcolor(moutercolor); moutpaint.setstyle(paint.style.stroke); moutpaint.setstrokecap(paint.cap.round);//圆角 minnerpaint = new paint(); minnerpaint.setantialias(true); minnerpaint.setstrokewidth(mborderwidth); minnerpaint.setcolor(minnercolor); minnerpaint.setstyle(paint.style.stroke);//实心 minnerpaint.setstrokecap(paint.cap.round);//圆角 mtextpaint = new paint(); mtextpaint.setantialias(true); mtextpaint.setstyle(paint.style.stroke); mtextpaint.setcolor(msteptextcolor); mtextpaint.settextsize(msteptextsize); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); int width = measurespec.getsize(widthmeasurespec); int height = measurespec.getsize(heightmeasurespec); int widthmode = measurespec.getmode(widthmeasurespec); int heightmode = measurespec.getmode(heightmeasurespec); if (widthmode == measurespec.at_most && heightmode == measurespec.at_most) { //用户设置的是wrap_content,此时设置一个默认宽高100 width = height = measureutils.dp2px(200, this); } setmeasureddimension(width > height ? height : width, width > height ? height : width); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); int center = getwidth() / 2; int radius = getwidth() / 2 - mborderwidth; rectf rectf = new rectf(mborderwidth, mborderwidth, center + radius, center + radius); canvas.drawarc(rectf, 135, 270, false, moutpaint); if (mseptmax == 0) return; float sweepangle = (float) mseptcurrent / mseptmax; canvas.drawarc(rectf, 135, 270 * sweepangle, false, minnerpaint); string steptext = mseptcurrent + ""; rect textbounds = new rect(); mtextpaint.gettextbounds(steptext, 0, steptext.length(), textbounds); int dx = getwidth() / 2 - textbounds.width() / 2; int baseline = measureutils.measurebaseline(mtextpaint, steptext, this); canvas.drawtext(steptext, dx, baseline, mtextpaint); } public void setmseptmax(int mseptmax) { this.mseptmax = mseptmax; } public synchronized void setmseptcurrent(int mseptcurrent) { this.mseptcurrent = mseptcurrent; //重绘 invalidate(); } }
import android.content.context; import android.content.res.typedarray; import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.graphics.rect; import android.graphics.rectf; import android.support.annotation.nullable; import android.util.attributeset; import android.view.view; import com.cyq.customview2.r; import com.cyq.customview2.utils.measureutils; @suppresswarnings("all") public class myprogressbar extends view { private int mliftcolor = color.parsecolor("#f44336"); private int mrightcolor = color.parsecolor("#e0e0e0"); private int mprogresstextcolor = color.parsecolor("#616161"); private int mprogresstextsize = 12;//px 后续再考虑需不需要转换成sp private int mprogressbounds = 1;//px private int mcurrentprogress, mmaxprogress = 100;//默认最大刻度为100 private paint mleftpaint, mrightpaint, mtextpaint; public myprogressbar(context context) { this(context, null); } public myprogressbar(context context, @nullable attributeset attrs) { this(context, attrs, 0); } public myprogressbar(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); typedarray array = context.obtainstyledattributes(attrs, r.styleable.myprogressbar); mliftcolor = array.getcolor(r.styleable.myprogressbar_leftcolor, mliftcolor); mrightcolor = array.getcolor(r.styleable.myprogressbar_rightcolor, mrightcolor); mprogresstextcolor = array.getcolor(r.styleable.myprogressbar_progresstextcolor, mprogresstextcolor); mprogresstextsize = array.getdimensionpixelsize(r.styleable.myprogressbar_progresstextsize, mprogresstextsize); array.recycle(); mleftpaint = new paint(); mleftpaint.setantialias(true); mleftpaint.setcolor(mliftcolor); mrightpaint = new paint(); mrightpaint.setantialias(true); mrightpaint.setcolor(mrightcolor); mtextpaint = new paint(); mtextpaint.setantialias(true); mtextpaint.setstyle(paint.style.stroke); mtextpaint.setcolor(mprogresstextcolor); mtextpaint.settextsize(mprogresstextsize); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); int widht = measurespec.getsize(widthmeasurespec); int height = measurespec.getsize(heightmeasurespec); setmeasureddimension(widht, height); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); mrightpaint.setstrokewidth(getheight()); rectf rightrect = new rectf(0, 0, getwidth(), getheight()); canvas.drawroundrect(rightrect, getheight() / 2, getheight() / 2, mrightpaint); mleftpaint.setstrokewidth(getheight()); float progress = (float) mcurrentprogress / (mmaxprogress * 10); int radius = getheight() / 2; rectf rectf = new rectf(0, 0, progress * getwidth(), getheight()); canvas.drawroundrect(rectf, radius, radius, mleftpaint); //画文字随着进度条右移 string text = (float) mcurrentprogress / 10 + "%"; int dx = getheight() / 2; rect textbounds = new rect(); mtextpaint.gettextbounds(text, 0, text.length(), textbounds); int baseline = measureutils.measurebaseline(mtextpaint, text, this); canvas.drawtext(text, progress * getwidth() + 10, baseline, mtextpaint); } public void setprogress(int mcurrentprogress) { this.mcurrentprogress = mcurrentprogress; //重绘 invalidate(); } public void setmaxprogress(int mmaxprogress) { this.mmaxprogress = mmaxprogress; } public int getprogress() { return mcurrentprogress; } }
3.为自定义view添加动画
首先在xml中使用我们的自定义布局和自定义属性
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".page3.qqsportactivity"> <com.cyq.customview2.page3.qqstepview android:id="@+id/custom_qq_step" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center_horizontal" android:layout_margintop="50dp" app:borderwidth="6dp" app:innercolor="@color/innercolor" app:outercolor="@color/outercolor" app:steptextsize="30sp" android:layout_marginbottom="100dp"/> <com.cyq.customview2.page3.myprogressbar android:id="@+id/custom_progressbar" android:layout_width="match_parent" android:layout_height="20dp" android:layout_margin="50dp" app:leftcolor="@color/innercolor" app:progresstextcolor="@color/steptextcolor" app:progresstextsize="16sp" app:rightcolor="@color/greycolor" /> </linearlayout>
通过属性动画动态增加进度
import android.animation.objectanimator; import android.animation.valueanimator; import android.os.bundle; import android.support.v7.app.appcompatactivity; import android.view.animation.decelerateinterpolator; import com.cyq.customview2.r; import butterknife.bindview; import butterknife.butterknife; public class qqsportactivity extends appcompatactivity { @bindview(r.id.custom_qq_step) qqstepview customqqstep; @bindview(r.id.custom_progressbar) myprogressbar customprogressbar; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_qqsport); butterknife.bind(this); customqqstep.setmseptmax(10000); //属性动画 valueanimator valueanimator = objectanimator.offloat(0, 8765); valueanimator.setduration(2000); valueanimator.setinterpolator(new decelerateinterpolator());//插值器 valueanimator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float currentstep = (float) animation.getanimatedvalue(); customqqstep.setmseptcurrent((int) currentstep); } }); valueanimator.start(); //属性动画 valueanimator valueanimator2 = objectanimator.offloat(0, 780); valueanimator2.setduration(2000); valueanimator2.setinterpolator(new decelerateinterpolator());//插值器 valueanimator2.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float currentstep = (float) animation.getanimatedvalue(); customprogressbar.setprogress((int) currentstep); } }); valueanimator2.start(); } }
获取文字基线和sp,dp转xp的工具类如下;
import android.graphics.paint; import android.graphics.rect; import android.util.typedvalue; import android.view.view; public class measureutils { /** * drawtext获取基线 * * @param textpaint * @param text * @param view * @return */ public static int measurebaseline(paint textpaint, string text, view view) { rect textbounds = new rect(); textpaint.gettextbounds(text, 0, text.length(), textbounds); paint.fontmetricsint fontmetricsint = textpaint.getfontmetricsint(); int dy = (fontmetricsint.bottom - fontmetricsint.top) / 2 - fontmetricsint.bottom; int baseline = view.getheight() / 2 + dy; return baseline; } public static int sp2px(int sp, view view) { return (int) typedvalue.applydimension(typedvalue.complex_unit_sp, sp, view.getresources().getdisplaymetrics()); } public static int dp2px(int dp, view view) { return (int) typedvalue.applydimension(typedvalue.complex_unit_dip, dp, view.getresources().getdisplaymetrics()); } }
后续待改进
1.sp,dp,xp的转换
2.进度文字接近100%时不向右边移动,并且文字和进度重叠部分动态变色