一个炫酷的SearchView搜索动画库

GloryGe 8年前
   <p>本文出自cjj的开源项目:<a href="/misc/goto?guid=4959670213295422993">一个炫酷的SearchView搜索动画库</a>。</p>    <p> </p>    <p>前言:周末强撸一个库,差点灰飞烟灭.无妨,人生自古谁无死,来生继续撸代码.</p>    <p>立马入主题,几乎每个App都有搜索功能,然而形式千篇一律。我举个例子吧,就微信来说:</p>    <p><img alt="blob.png" src="https://simg.open-open.com/show/6d131b0a07d557f54bc7bf2abe50b4ca.png"></p>    <p><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">显示一个搜索的图标,点击跳到另一个界面,输入要搜索的东西</span></p>    <p> </p>    <p><img alt="blob.png" src="https://simg.open-open.com/show/daa6ceac736341a50c15726cc5436e4f.png"></p>    <p>现在大部分App都是用这种方式了。我是希望能有App把这个功能做得酷炫点,毕竟它也是用户经常要用到的,给用户良好的体验还是很重要的。 为此,我实现了别人设计的一些SearchView酷炫效果,可能不是很精致,你就勉强看看吧。</p>    <p>此时,如果你看完表格那些动画,喜欢上它时,想知道他们是怎么在代码中实现的,没问题,我这就手把手教你撩一个绚丽的SearchViewAnim , 呵呵,有点吹大了,说说我怎么实现的吧。</p>    <h3>实现思路</h3>    <p>我们先对第一行表格的设计图进行仔细观察 ,效果是SearchView是由一个圆圈和一条直线(尾巴)构成的,开启动画时,尾巴慢慢消失成一点,然后这一点(dot) 进入圆圈内时,泛起波纹,在圈内四处逗留,然后在圆圈中心点停留闪烁,短暂的思考了下人生,又冲出去乖乖做一条尾巴。</p>    <p>咳,这是一个顿悟生命的dot啊!</p>    <p>相信大家通过我形象的描述已经知道效果是怎样了,现在就把刚刚描叙的画出来吧。</p>    <h3>实现绘制</h3>    <p>(1) 自定义类SearchView继承View</p>    <p><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">重写</span><code>onDraw(Canvas canvas)</code><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">方法,利用画笔Paint在画布Canvas绘制一个普通的的视图,如下:</span></p>    <p><img alt="blob.png" src="https://simg.open-open.com/show/1544cf08476c0de536f2dc1266bb522b.png"></p>    <p>这里有两种画法:</p>    <p>1.横向画圆、画直线后,旋转画布45度</p>    <pre>  canvas.rotate(45, cx, cy);  canvas.drawLine(cx + cr, cy, cx + cr * 2, cy, paint);  canvas.drawCircle(cx, cy, cr, paint);</pre>    <p><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">2.直接算出坐标点绘制</span></p>    <pre>   canvas.drawCircle(cx, cy, cr, paint);   canvas.drawLine(cx + cr * sign, cy + cr * sign, scx, cy + cr * 2 * sign, paint);</pre>    <p><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">这一步比较简单,就不多说了。</span></p>    <p>(2) 实现动画效果,这里的动画有dot进入圈圈时泛起的波浪效果和dot在圈圈内的运行轨迹。</p>    <p><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">因为运行轨迹是固定的,我们把经过的路径设置给Path,在构造</span><code>PathMeasure</code><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">函数(不知道PathMeasure用法的同学自己搜索学习),使用它两个方法</span><code>getLength()</code><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">,.可获取dot运行路径的长度,</span><code>getPosTan(float distance, float pos[],float tan[])</code><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">可根据distance可以获取dot的坐标点pos[]. 写成代码就是:</span></p>    <pre>  //创建0~mPathMeasure.getLength()的过度动画值   ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());   valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {              @Override              public void onAnimationUpdate(ValueAnimator valueAnimator) {                  mPro = (float) valueAnimator.getAnimatedValue();                  if (null != pathMeasure)                      pathMeasure.getPosTan(mPro, mPos, null);//获取当前点坐标保存到mPos[]                  getSearchView().invalidate();//调用ondraw()函数              }          });</pre>    <p><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">至于dot进入圈圈时泛起的波浪效果,其实就是曲线的不断扩大而已,这里我们可以利用贝塞尔函数</span><code>quadTo()</code><span style="background-color:rgb(255, 255, 255); color:rgb(51, 51, 51)">,不断改变控制点来实现该效果。</span></p>    <p>(3)收尾Reset</p>    <p>因为结束动画之后,视图和开始时一样,所以我们并不需要绘制Reset时的动画,只需重置状态就可以了,而如果是有些情况,比如动画停止后是箭头的效果,就需要要逆着回去绘制SearchView的过程了。</p>    <p>其他动画效果也是这样一步一步把复杂的东西简单化,最后你发现无非就是画线、画曲线、画弧、画圆这些,我就偷个懒,不讲剩下效果的的实现方式了,自己看看源码,可能比我吹水有用的多。</p>    <h3>杂谈</h3>    <p>写这些花费的时间、精力还是挺多的,因为需要一些数学计算(我数学烂)和不断的调试才能绘制满意的效果,所以建议如果项目需要,可以在别人实现的轮子上改改就好。我们都知道,一个App只能有一种风格,所以加入很多样式的动画是没必要的,修改一种合适自己的就好。</p>    <p>水平有限及写的随意,该库还是有不少问题,也希望你能PR,完善它。</p>    <p>来源:<a href="/misc/goto?guid=4959670213373757054">陈继军</a></p>