Android自定义view Path 的高级用法之搜索按钮动画
关于path之前写的也很多了,例如path绘制线,path绘制一阶,二阶和三阶贝塞尔路径,这些都是path的基本用法。今天我要带大家看的是path 的高级用法,先上图,再吹。
效果大致是这样的。看着是不是挺好。话不多说,切入正题:
既然今天要谈path的高级用法,那就先来讲一讲(path -- 中文 )就是“路径”既然是路径,从我们面向对象的想法的话,我们就容易想到 路径 的长度,路径的某一点等。想到这里我们就引出今天 的主要 类--------pathmeasure,字面意思很容易理解--翻译成 路径测量。对这就是我们用来测量路径的类。既然是一个类,我们就要看他集体有哪些方法和属性。
1.构造方法:
一个是有参数,一个无参数。
无参数就很容易理解就是直接创建对象,那有参数呢?
pathmeasure(path path, boolean forceclosed) ;
第一个参数 path 咿 !这不就是我们的path 了吗。对既然是测量类,那就是要确定需要测量的那个路径,那第二个参数呢?
第二个参数是用来确保 path 闭合,如果设置为 true, 则不论之前path是否闭合,都会自动闭合该 path(如果path可以闭合的话)。
2.方法:
这方法还挺多,都是干啥的呢?就找几个重要的,常用的讲讲:
第一个那就是 setpath(path path, boolean forceclosed)
这方法一看就知道设置path 路径的,就是如果我们创建 pathmeasure,时用的是无参的构造方法时 ,这时候就要用此方法,告诉pathmeasure 当前需要测量的是哪一个path路径。(个人喜欢用无参,比较灵活)。
第二个那就是getlength(),很容易理解就是 获得 path 的总长度。
第三个:getsegment(float startd, float stopd, path dst, boolean startwithmoveto),这个方法非常重要,截取片段,截取的结果就是,我们的path路径。参数也很好理解。第一个是开始的距离,第二个是结束的距离(相对于起点==既然是起点,我们怎么找他们的起点呢,其实就是我们绘制图画笔开始的哪一点)。第三个参数就是返回的路径。第四个参数起始点是否使用 moveto 用于保证截取的 path 第一个点位置不变。
第四个:getpostan(float distance, float[] pos, float[] tan),这个也是非常重要的,为什么呢?听我解释一下他的参数就知道了。第一个参数是距离(相对于绘制起点的路径距离),第二个参数是距离起点的坐标点,第三个参数返回的是正玄函数tan@角度。
对这些参数了解之后下面就来讲解我们今天的例子:
首先我们先来个简单的:例如
如图这样的分析过程:
1.首先绘制一个圆(蓝色的),从45度开始绘制,注意圆的起点。
2.同圆心绘制大圆(辅助圆)用来辅助绘制蓝色的线。
3.通过getpostan(float distance, float[] pos, float[] tan)方法得到两个圆的终点的坐标。
4.利用lineto(x,y)绘制线。就得到我们的搜索图形了。
5.接下来就是实时 截取片段。getsegment(float startd, float stopd, path dst, boolean startwithmoveto),截取从距离0到getlength();这样就产生了一个动态的效果了。
看代码:
关于画笔,canvas画布,valueanimator动画,这些请看之前的博客,都有详细讲解。
public class mysearch extends view { paint paint; path searchpath; //搜索的圆 path ciclepath; //外圆 //获得宽高 int w; int h; //这是保存截取时,返回的坐标点 float serpos[]; float cicpos[]; //测量 path 的类 pathmeasure measure; //动画产生的实时数据 float value; public mysearch(context context) { this(context,null); } public mysearch(context context, @nullable attributeset attrs) { this(context,attrs,0); } public mysearch(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); //获得屏幕的宽高 windowmanager wm = (windowmanager) context.getsystemservice(context.window_service); w = wm.getdefaultdisplay().getwidth(); h = wm.getdefaultdisplay().getheight(); //初始化数据 serpos = new float[2]; cicpos = new float[2]; //画笔 paint = new paint(); paint.setstyle(paint.style.stroke); paint.setdither(true); paint.setstrokewidth(6); paint.setantialias(true); //初始化路径 initpath(); //初始化动画 initanimator(); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); //移动画布的远点到屏幕中心 canvas.translate(w/2,h/5); paint.setcolor(color.blue); //这是截取方法返回的路径 path dra = new path(); //解除硬件加速,不然没效果 dra.reset(); dra.lineto(0,0); //设置当前需要测量的path measure.setpath(searchpath,false); //开始截取 boolean s = measure.getsegment(measure.getlength()*value,measure.getlength(),dra,true); //绘制路径 canvas.drawpath(dra,paint); } /** * 初始化路径 */ public void initpath(){ paint.setcolor(color.blue); //搜索的圆 searchpath = new path(); rectf rectf = new rectf(-50,-50,50,50); searchpath.addarc(rectf,45,359.9f); //辅助圆 ciclepath = new path(); rectf rectf1 = new rectf(-100,-100,100,100); ciclepath.addarc(rectf1,45,359.9f); //测量类 measure = new pathmeasure(); measure.setpath(searchpath,false); //获取坐标 measure.getpostan(0,serpos,null); measure.setpath(ciclepath,false); //获取坐标 measure.getpostan(0,cicpos,null); //根据两点坐标绘制线 searchpath.lineto(cicpos[0],cicpos[1]); } /** * 初始化动画 */ public void initanimator(){ valueanimator animator = valueanimator.offloat(0,1); animator.setduration(2600); animator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { value = (float) animation.getanimatedvalue(); postinvalidate(); } }); animator.start(); } }
第一个图大家学会了,去练习一下吧!