召唤,光能使者--玩转PathMeasure

801 阅读4分钟

作者博客

http://www.jianshu.com/u/975e915e131b

文章目录

  • 前言

  • PathMeasure

  • 动画拆解

  • 代码实现

0

前言

首先我们来回顾一下童年吧~~90后满满的记忆

小时候总是幻想着自己能变身,今天我们就来用代码实现变身的第一步吧,动画绘制一个魔法阵magic_circle~~

静态图片比较容易,我们用 Path 设置好路径,然后再 canvas.drawPath 即可,但是静态的也太 low 了一点,我们要让它动起来。

效果看完了,不会写的童鞋肯定已经懵逼了,会的童鞋可以出门左拐了,因为实现实在太简单。

好了,在开始撸代码之前,我们先来学习一个类 PathMeasure。我们的光能使者阵就是是基于这个类的两个方法撸出来的。

1

PathMeasure

这个类的 class 注释就一个版权说明,酱紫~

踏马的,Google 工程师都偷懒了,注释都不写。。。幸好这个类只有一百多行代码,那我们就自己看吧

Public constructors

  • PathMeasure 创建一个空的 pathmeasure 对象

  • PathMeasure(Path path,boolean forceClosed)创建一个带 path 参数的 PathMeasure,forceClosed控制 path 是否自动闭合

Public methods

  • getLength() 返回当前 Path 的总长度。

  • getMatrix(float distance, Matrix matrix, int flags)

  • getPosTan(float distance, float[] pos, float[] tan)获取distance长度的 point 值给 pos,point 点的正切值给 tan。

  • getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) 获取 path 的一个片段,即startD到 stopD 的线段,辅助给 dst。

  • isClosed() 是否自动闭合

  • nextContour() 移动到下一条曲线。如果 path 中含有不连续的线条,getLength、getPosTan等方法之会在第一条线上运行,需要使用这个方法跳到第二条线

  • setPath(Path path, boolean forceClosed)

是不是很简单,就这么几个方法,现在去画光能使者阵有思路了么~~接下来为了便于大家理解,我们再来简单回顾一下 path 的 api,因为静态的光能使者阵是需要 path 去绘制的。

Path

就这样简单回顾一下吧,具体玩法可以参考 Hencoder 的 bolg

2

动画拆解

好了,准备工作完成,我们开始撸代码

第一步,绘制静态的光能使者阵

首先绘制两个圆,然后就是中间的六角星(其实仔细看就是两个三角形)。都是很简单的方法,同学们动手去画的时候可能会遇到一个这样的问题,就是三角形的三个点不好取。其实很简单,直接在圆上取0,1/3,2/3长度的点即可,刚刚我们不是说了 PathMeasure 的方法么,用getPosTan就可以实现。

第二步,让光能使者阵动起来

这里我们把这个动画效果分成三个阶段吧。

第一阶段,绘制两个圆

如上图所示,这里两个圆是慢慢绘制出来的, 圆的 path 很容易绘制出来,这里我就不讲了,然后PathMeasure的getLength可以获取 path 总的长度,getSegment可以获取某个点到某个点的 Path。因此一个 ValueAnimator 就可以解决从0到100%长度的过程,具体实现看后面的代码。

然后问题来了,path画出来的圆的起点在哪里?怎么控制两个圆开始绘制的角度不一样。有同学可能想到了旋转90°再画第二个圆,当然这种方式是可以实现的,但是由于后面的三角形也需要旋转,这里我们就不用 path 画圆了,用 path 添加一个正方形 Rect 的圆弧也是一个圆,然后我们的圆弧可以控制开始的角度,弧度。然后变成这样了

WTF?角度怎么不对了,我明明设置的开始角度的呀

innerCircle.addArc(innerRect, 150, -360);outerCircle.addArc(outerRect, 60, -360);

最后有个大牛说你的圆变成闭环了,PathMeasure 找不到开始点,用了默认的。你把360度改成359.9让他不是一个闭环的圆就行了。

第二阶段,两个点在圆里面弹射

看起来好像还要干什么碰撞反弹之类的事,一副高科技的样子,其实不是的。

轨迹就是两个三角形,怎么让两条线跟着三角形走呢,而且走的时候还要不段变化长度。

刚刚第一步我们用 ValueAnimator 来控制一个圆从0到100%的过程,

pathMeasure.getSegment(0, distance * pathMeasure.getLength(), drawPath, true);

不断截取起点到*%长度的 path 赋值给drawPath。

从里是从起点开始截取,那么我们不从起点开始截取,从当前点附近开始截取不就行了吗,哈哈哈哈~so easy

float stopD = distance * pathMeasure.getLength();float startD = stopD - (0.5f - Math.abs(0.5f - distance)) * 200;pathMeasure.getSegment(startD, stopD, drawPath, true);

第三阶段绘制两个三角形

其实两个三角形就是第二步的运动轨迹,也是就是说直接用第阶段的 Path 即可,然后再用第一阶段一样的办法就可以实现效果。

3

代码实现

干货推荐

如何在移动开发者的寒冬中破冰而出?