Android 开发订单流程view实例详解
程序员文章站
2023-11-15 20:24:22
android 开发订单流程view实例详解
先看看最终效果图:
怎么样,效果还是很不错的吧?群里有人说切四张图的、recycleview的、各种的都有...
android 开发订单流程view实例详解
先看看最终效果图:
怎么样,效果还是很不错的吧?群里有人说切四张图的、recycleview的、各种的都有啊,但是最简单的就是通过自定义view来实现了~接下来让我们来实现下这个(订单流程view)。
首先我们定义好我们的自定义属性:
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="processview"> <!--滑动圆点的半径--> <attr name="thumb_radius" format="dimension"/> <!--到达的颜色--> <attr name="color_reached" format="color"/> <!--未到达的颜色--> <attr name="color_unreached" format="color"/> <!--textsize的大小--> <attr name="textsize" format="dimension"/> <!--text的颜色--> <attr name="text_color" format="color"/> <!--线的宽度--> <attr name="line_width" format="dimension"/> <!--状态文字数组--> <attr name="texts" format="reference"/> </declare-styleable> </resources>
然后就是我们的老套路了,创建一个叫processview的类继承view,然后定义好我们需要的属性:
/** * created by leo on 17/3/27. */ public class processview extends view { /** * 默认线宽度 */ private static final float d_line_width = 3; /** * 默认滑动圆点半径 */ private static final float d_thumb_radius = 10; /** * 默认textsize */ private static final float d_text_size = 13f; private static final int d_reach_color = 0xfff1ae0d; private static final int d_unreach_color = color.white; private static final int d_text_color = color.white; private paint linepaint; private textpaint textpaint; private paint thumbpaint; private float mtextsize = xx2px(typedvalue.complex_unit_sp, d_text_size); private float mlinewidth = xx2px(typedvalue.complex_unit_dip, d_line_width); private float mthumbradius = xx2px(typedvalue.complex_unit_dip, d_thumb_radius); private int mreachedcolor = d_reach_color; private int munreachedcolor = d_unreach_color; private int mtextcolor = d_text_color; //当前进度 private float mprogress = 0.0f; //所有的状态文字 private string[] texts; public processview(context context) { this(context, null); } public processview(context context, attributeset attrs) { this(context, attrs, 0); } public processview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); obtainstyledattrs(context, attrs, defstyleattr); initviews(); } /** * 获取我们的自定义属性 * @param context * @param attrs * @param defstyleattr */ private void obtainstyledattrs(context context, attributeset attrs, int defstyleattr) { typedarray a = context.obtainstyledattributes(attrs, r.styleable.processview, defstyleattr, 0); texts = a.hasvalue(r.styleable.processview_texts) ? getresources().getstringarray(a.getresourceid(r.styleable.processview_texts, 0)) : texts; mlinewidth = a.hasvalue(r.styleable.processview_line_width) ? a.getdimensionpixelsize(r.styleable.processview_line_width, 0) : mlinewidth; mthumbradius = a.hasvalue(r.styleable.processview_thumb_radius) ? a.getdimensionpixelsize(r.styleable.processview_thumb_radius, 0) : mthumbradius; mtextsize = a.hasvalue(r.styleable.processview_textsize) ? a.getdimensionpixelsize(r.styleable.processview_text_color, 0) : mtextsize; mreachedcolor=a.hasvalue(r.styleable.processview_color_reached)? a.getcolor(r.styleable.processview_color_reached,d_reach_color):d_reach_color; munreachedcolor=a.hasvalue(r.styleable.processview_color_unreached)? a.getcolor(r.styleable.processview_color_unreached,d_unreach_color):d_unreach_color; mtextcolor=a.hasvalue(r.styleable.processview_text_color)? a.getcolor(r.styleable.processview_text_color,d_text_color):d_text_color; a.recycle(); } /** * 初始化一些对象 */ private void initviews() { linepaint = new paint(paint.anti_alias_flag | paint.dither_flag); linepaint.setstyle(paint.style.fill); textpaint = new textpaint(paint.anti_alias_flag | paint.dither_flag); thumbpaint = new paint(linepaint); textpaint.settextsize(mtextsize); textpaint.setcolor(mtextcolor); linepaint.setstrokewidth(mlinewidth); } }
然后就是重写我们的onmeasure方法了,我们这里就不考虑控件的高度为wrap_content这种情况了,所以我们只需要测量高度就可以了:
@override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int heightm = measurespec.getmode(heightmeasurespec); int defaultw = measurespec.getsize(widthmeasurespec); int defaulth = measurespec.getsize(heightmeasurespec); int resultw, resulth; resultw = defaultw; resulth = getdefaultheight(defaulth, heightm); setmeasureddimension(resultw, resulth); } private int getdefaultheight(int height, int mode) { int result; if (mode == measurespec.exactly) { result = height; } else { //获取文字的高度 float texth = (textpaint.getfontmetrics().bottom - textpaint.getfontmetrics().top); //高度=圆半径+2.2*线条宽度(也就是竖线高度)+文字高度*1.3(也就是空隙高度)+0.5*文字高度 result = (int) (mthumbradius + mlinewidth * 2.2f + texth * 1.3f + 0.5 * texth); } return result; }
接着就是我们的核心方法ondraw()了,代码很简单都有注释,我就不一一解释了:
@override protected void ondraw(canvas canvas) { //画底部的竖线跟文字 drawfoot(canvas); //画移动的小圆点跟进度条 drawprogressandthumb(canvas); } /** * 画底部的竖线跟文字 */ private void drawfoot(canvas canvas) { //设置底部竖线宽度(底部的竖线会比进度条的要小一点) float linewidth = mlinewidth * 0.8f; linepaint.setstrokewidth(mlinewidth * 0.8f); //起始位置(也就是"订单已提交"的"已"字位置) float startx = textpaint.measuretext(texts[0]) / 2; //结束的文字的位置("已送达"的"送"字位置) float endtextw = textpaint.measuretext(texts[texts.length - 1]) / 2; //绘制的终点位置 float endx = getmeasuredwidth() - endtextw; //线条的总长度 float linew = (endx - startx) / (texts.length - 1); //竖线的高度 float lineh = mlinewidth * 2.2f; //竖线的终点位置 float liney = mthumbradius + mlinewidth / 2; //循环画出竖线跟文字 for (int i = 0; i < texts.length; i++) { canvas.save(); //每画一条竖线让画布水平平移linew个宽度 canvas.translate(i * linew, 0); //如果当前进度>竖线所在的位置,就改变竖线的颜色 linepaint.setcolor(i * linew >= mprogress * (endx - startx) ? munreachedcolor : mreachedcolor); float endx2 = i == texts.length - 1 ? startx - linewidth / 2 : startx + linewidth / 2; canvas.drawline(endx2, liney, endx2, liney + lineh, linepaint); //画文字 textpaint.settextalign(paint.align.center); float texth = (textpaint.getfontmetrics().bottom - textpaint.getfontmetrics().top); canvas.drawtext(texts[i], endx2, liney + lineh + texth * 1.3f, textpaint); canvas.restore(); } } private void drawprogressandthumb(canvas canvas) { float startx = textpaint.measuretext(texts[0]) / 2; float endtextw = textpaint.measuretext(texts[texts.length - 1]) / 2; float endx = getmeasuredwidth() - endtextw; float liney = mthumbradius; linepaint.setstrokewidth(mlinewidth); //draw basic line linepaint.setcolor(munreachedcolor); canvas.drawline(startx, liney, endx, liney, linepaint); //draw progress line float progressx = startx + (endx - startx) * mprogress; linepaint.setcolor(mreachedcolor); canvas.drawline(startx, liney, progressx, liney, linepaint); //给移动圆点一个radialgradient颜色梯度效果 thumbpaint.setshader(new radialgradient(progressx, mthumbradius, mthumbradius, new int[]{color.white, d_reach_color, color.yellow}, null, shader.tilemode.repeat)); canvas.drawcircle(progressx, mthumbradius, mthumbradius, thumbpaint); }
好啦~~然后我们暴露一个方法给外部,修改progress:
public void setprogress(float progress) { if (progress != mprogress) { mprogress = progress; if (looper.mylooper() == looper.getmainlooper()) { invalidate(); } else { postinvalidate(); } } }
最后我们就可以跑起来了:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" android:paddingbottom="@dimen/activity_vertical_margin" android:background="#b2000000" android:orientation="vertical" > <android.support.v7.widget.cardview android:layout_width="match_parent" android:layout_height="wrap_content" app:cardcornerradius="5dp" app:cardelevation="3dp" app:cardbackgroundcolor="#ff2384dd" > <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="10dp" > <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="商家已接单" android:textsize="14.5sp" android:textcolor="#fff1ae0d" /> <textview android:layout_margintop="5dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="订单超过12小时自动完成" android:textsize="13sp" android:textcolor="#fff" /> <view android:layout_margintop="10dp" android:layout_marginbottom="10dp" android:layout_width="match_parent" android:layout_height="2dp" android:background="@drawable/bg_line" android:layertype="software" /> <com.yasin.processdemo.view.processview android:id="@+id/id_process" android:layout_width="match_parent" android:layout_height="wrap_content" app:texts="@array/process_states" /> </linearlayout> </android.support.v7.widget.cardview> </linearlayout>
arrays.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <array name="process_states"> <item>订单已提交</item> <item>已付款</item> <item>商家已接单</item> <item>已送达</item> </array> </resources>
然后是我们的测试activity:
package com.yasin.processdemo; import android.animation.valueanimator; import android.os.bundle; import android.support.v7.app.appcompatactivity; import android.view.animation.acceleratedecelerateinterpolator; import com.yasin.processdemo.view.processview; public class mainactivity extends appcompatactivity { private processview mprocessview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mprocessview= (processview) findviewbyid(r.id.id_process); startani(); } private void startani() { valueanimator a = valueanimator.offloat(0, 1); a.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float progress = (float) animation.getanimatedvalue(); mprocessview.setprogress(progress); } }); a.setduration(10000); a.setinterpolator(new acceleratedecelerateinterpolator()); a.start(); } }
最后附上processview的全部代码:
package com.yasin.processdemo.view; import android.content.context; import android.content.res.resources; import android.content.res.typedarray; import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.graphics.radialgradient; import android.graphics.shader; import android.os.looper; import android.text.textpaint; import android.util.attributeset; import android.util.log; import android.util.typedvalue; import android.view.view; import com.yasin.processdemo.r; /** * created by leo on 17/3/27. */ public class processview extends view { /** * 默认线宽度 */ private static final float d_line_width = 3; /** * 默认滑动圆点半径 */ private static final float d_thumb_radius = 10; /** * 默认textsize */ private static final float d_text_size = 13f; private static final int d_reach_color = 0xfff1ae0d; private static final int d_unreach_color = color.white; private static final int d_text_color = color.white; private paint linepaint; private textpaint textpaint; private paint thumbpaint; private float mtextsize = xx2px(typedvalue.complex_unit_sp, d_text_size); private float mlinewidth = xx2px(typedvalue.complex_unit_dip, d_line_width); private float mthumbradius = xx2px(typedvalue.complex_unit_dip, d_thumb_radius); private int mreachedcolor = d_reach_color; private int munreachedcolor = d_unreach_color; private int mtextcolor = d_text_color; //当前进度 private float mprogress = 0.0f; //所有的状态文字 private string[] texts; public processview(context context) { this(context, null); } public processview(context context, attributeset attrs) { this(context, attrs, 0); } public processview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); obtainstyledattrs(context, attrs, defstyleattr); initviews(); } /** * 获取我们的自定义属性 * @param context * @param attrs * @param defstyleattr */ private void obtainstyledattrs(context context, attributeset attrs, int defstyleattr) { typedarray a = context.obtainstyledattributes(attrs, r.styleable.processview, defstyleattr, 0); texts = a.hasvalue(r.styleable.processview_texts) ? getresources().getstringarray(a.getresourceid(r.styleable.processview_texts, 0)) : texts; mlinewidth = a.hasvalue(r.styleable.processview_line_width) ? a.getdimensionpixelsize(r.styleable.processview_line_width, 0) : mlinewidth; mthumbradius = a.hasvalue(r.styleable.processview_thumb_radius) ? a.getdimensionpixelsize(r.styleable.processview_thumb_radius, 0) : mthumbradius; mtextsize = a.hasvalue(r.styleable.processview_textsize) ? a.getdimensionpixelsize(r.styleable.processview_text_color, 0) : mtextsize; mreachedcolor=a.hasvalue(r.styleable.processview_color_reached)? a.getcolor(r.styleable.processview_color_reached,d_reach_color):d_reach_color; munreachedcolor=a.hasvalue(r.styleable.processview_color_unreached)? a.getcolor(r.styleable.processview_color_unreached,d_unreach_color):d_unreach_color; mtextcolor=a.hasvalue(r.styleable.processview_text_color)? a.getcolor(r.styleable.processview_text_color,d_text_color):d_text_color; a.recycle(); } /** * 初始化一些对象 */ private void initviews() { linepaint = new paint(paint.anti_alias_flag | paint.dither_flag); linepaint.setstyle(paint.style.fill); textpaint = new textpaint(paint.anti_alias_flag | paint.dither_flag); thumbpaint = new paint(linepaint); textpaint.settextsize(mtextsize); textpaint.setcolor(mtextcolor); linepaint.setstrokewidth(mlinewidth); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int heightm = measurespec.getmode(heightmeasurespec); int defaultw = measurespec.getsize(widthmeasurespec); int defaulth = measurespec.getsize(heightmeasurespec); int resultw, resulth; resultw = defaultw; resulth = getdefaultheight(defaulth, heightm); setmeasureddimension(resultw, resulth); } private int getdefaultheight(int height, int mode) { int result; if (mode == measurespec.exactly) { result = height; } else { //获取文字的高度 float texth = (textpaint.getfontmetrics().bottom - textpaint.getfontmetrics().top); //高度=圆半径+2.2*线条宽度(也就是竖线高度)+文字高度*1.3(也就是空隙高度)+0.5*文字高度 result = (int) (mthumbradius + mlinewidth * 2.2f + texth * 1.3f + 0.5 * texth); } return result; } @override protected void ondraw(canvas canvas) { //画底部的竖线跟文字 drawfoot(canvas); //画移动的小圆点跟进度条 drawprogressandthumb(canvas); } /** * 画底部的竖线跟文字 */ private void drawfoot(canvas canvas) { //设置底部竖线宽度(底部的竖线会比进度条的要小一点) float linewidth = mlinewidth * 0.8f; linepaint.setstrokewidth(mlinewidth * 0.8f); //起始位置(也就是"订单已提交"的"已"字位置) float startx = textpaint.measuretext(texts[0]) / 2; //结束的文字的位置("已送达"的"送"字位置) float endtextw = textpaint.measuretext(texts[texts.length - 1]) / 2; //绘制的终点位置 float endx = getmeasuredwidth() - endtextw; //线条的总长度 float linew = (endx - startx) / (texts.length - 1); //竖线的高度 float lineh = mlinewidth * 2.2f; //竖线的终点位置 float liney = mthumbradius + mlinewidth / 2; //循环画出竖线跟文字 for (int i = 0; i < texts.length; i++) { canvas.save(); //每画一条竖线让画布水平平移linew个宽度 canvas.translate(i * linew, 0); //如果当前进度>竖线所在的位置,就改变竖线的颜色 linepaint.setcolor(i * linew >= mprogress * (endx - startx) ? munreachedcolor : mreachedcolor); float endx2 = i == texts.length - 1 ? startx - linewidth / 2 : startx + linewidth / 2; canvas.drawline(endx2, liney, endx2, liney + lineh, linepaint); //画文字 textpaint.settextalign(paint.align.center); float texth = (textpaint.getfontmetrics().bottom - textpaint.getfontmetrics().top); canvas.drawtext(texts[i], endx2, liney + lineh + texth * 1.3f, textpaint); canvas.restore(); } } private void drawprogressandthumb(canvas canvas) { float startx = textpaint.measuretext(texts[0]) / 2; float endtextw = textpaint.measuretext(texts[texts.length - 1]) / 2; float endx = getmeasuredwidth() - endtextw; float liney = mthumbradius; linepaint.setstrokewidth(mlinewidth); //draw basic line linepaint.setcolor(munreachedcolor); canvas.drawline(startx, liney, endx, liney, linepaint); //draw progress line float progressx = startx + (endx - startx) * mprogress; linepaint.setcolor(mreachedcolor); canvas.drawline(startx, liney, progressx, liney, linepaint); //给移动圆点一个radialgradient颜色梯度效果 thumbpaint.setshader(new radialgradient(progressx, mthumbradius, mthumbradius, new int[]{color.white, d_reach_color, color.yellow}, null, shader.tilemode.repeat)); canvas.drawcircle(progressx, mthumbradius, mthumbradius, thumbpaint); } public void setprogress(float progress) { if (progress != mprogress) { mprogress = progress; if (looper.mylooper() == looper.getmainlooper()) { invalidate(); } else { postinvalidate(); } } } private float xx2px(int unit, float value) { context c = getcontext(); resources r; if (c == null) r = resources.getsystem(); else r = c.getresources(); return (typedvalue.applydimension( unit, value, r.getdisplaymetrics())); } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!