Tips:由于简书好像不支持Latex公式,所以为了效果,有关公式部分截取了我发表在CSDN上的博文,地址:AZZ的博客
相信很多朋友和我一样很喜欢QQ上“一键退朝”的功能,就是把红点从它原本的地方拉走,消息提醒也就没有了。
一键退朝功能示意图直到如今我还是觉得这个功能很酷炫!于是想自己实现一番,经过一番调查知道拉伸其实就是由两个圆加上两条贝塞尔曲线组成的形状。
来看看腾讯设计师是怎么设计出来的吧:《QQ手机版 5.0“一键下班”设计小结》
看完了这个对实现思路有很大的帮助,可是我还是不能知道具体是怎么计算实现的,网上大部分的教程都是假想成了两个同样大小的圆来计算,这太取巧了!因为同样大小的圆两条外公切线是平行的,同一个圆上的公切点相连是会垂直于连心线的,但是大小不同的圆并没有这个特殊性!
另外网上也有很多仿照的项目,可是看算法看得头都大了也不明白为什么是这样算的!经过两天的研究,把初中数学(圆、三角函数等相关知识)好好复习了一遍,终于搞清楚了其中算法,现在跟我一起来看看吧!
1.得到连心线
通过观察可以发现,在“一键退朝”这个功能当中,有一个小圆固定在原来坐标位置不动的,只是半径会发生变化,另一个大圆是跟随着我们手指滑动到屏幕的位置来确定圆心坐标的,一般大圆的半径是固定的。
建立两圆的相对坐标系:
PS:在移动端的坐标系 y 轴是向下的。
假设某一个时刻,两圆的状态如图,我们现在可以确定的是小圆的圆心坐标 O 为(startX, startY),大圆的圆心坐标 P0 为 (x0, y0),以及小圆的半径 r 和大圆的半径 R 。
那么首先可以把连心线求出来!也就是 O P0 的距离。
2.求切点坐标
复习一下初中数学:
两个外离的圆,一定有两条外公切线。若两圆半径相同,则两外公切线平行;否则相交于一点,且该点与两圆心在同一直线。
我们再作一张有公切线的图:
切点为 P1、P2、P3、P4,我们现在目的就要求出这四个点,然后就能够在程序中画出切线。
整个算法最难的地方恐怕就是求这四个点了,我们需要借助作图来帮助计算,这之前还需要先复习下定理:
圆心和切点的连线一定垂直于过该点的公切线
再作几个辅助点 A、B、C、D,AB 表示以大圆圆心为原点的坐标系的 x 轴的两端,CD 表示以小圆圆心为原点的坐标系的 x 轴的两端,
3.求剩下两个切点的坐标
一开始我以为 P3、P4 的算法和 P1、P2 一样,就是把上面的减号换成加号就可以了。可是后来验证后发现不对, P3、P4 不能直接使用 β 进行运算。
为了能愉快阅读,再来复习一下各种拉丁希腊符号叫法:
α 阿尔法 β 贝塔 γ 伽玛 δ 德尔塔 ε 伊普西隆 ζ 泽塔
如上图作辅助线。
4.画贝塞尔曲线
把四个切点坐标求出来了,后面就简单了,现在就是以切线为原轴,画贝塞尔曲线了,不过我们还缺少一个控制点的坐标。
4.1 科普贝塞尔
怕有不清楚贝塞尔曲线的朋友,我科普一下先,简单来说就是求一段平滑曲线的公式。
如果我们把画一条直线分为进度100%的话,那么当进度为0%,12%,58%,74%时,画线的状态为(注意红色部分末的黑色端点,灰色部分为路径指示)
那么把所有时刻的黑点连接起来就构成了直线:
这个概念应该比较容易接受,好了继续。
二次贝塞尔曲线(最简单的贝塞尔曲线)的作法首先需要两个点确定一条直线,另外在直线外确定一点(即控制点),然后此时三点会形成三个线段,即下图的P0 P2、P0 P1和 P1 P2$(其实不用关注 P0 P2)
这只是进度为0时候的状态,按照上面概念,当进度 t 从 0 变化到 100 时的某一个时刻,比如 30, 66 ,99,那么各个时刻 P0 P1 和 P1 P2 的状态为
t=30 t=66 t=99可以发现,在 P0 P1 和 P1 P2 上有一直运动的两个点,我们将这两个点连接起来又形成一段新的线段,而在不同时刻,在这个新线段上同样会有一个运动的点,这个点也遵守 t 的变化。
t=30 t=66 t=99把所有时刻的黄色点连接起来,就形成了二阶贝塞尔曲线。
还不能理解的可以看下这个视频 - > 《bezier curve原理》- > 只要看就好,听不懂英文的可以把声音关掉。
bezier curve原理
费这么大劲把二阶贝塞尔讲了一遍,我们这里其实也只用到了二阶,高阶我就不讲了,一通百通。
4.2.寻找控制点
那么现在线段已经能确定了,就是两条公切线线段(P1P2、P3P4),那么控制点在哪呢?
这个其实有点靠猜了=。= 一开始我觉得应该在连心线的中点,其实实现后效果也还行,后来参照腾讯设计师的想法效果更好,他令 P1P2 的控制点为 P1P4 的中点,令 P3P4 的控制点为 P2P3 的中点。
软件实现效果对比(上边控制点是连心线的中点,下边是腾讯设计师提出的控制点):
我个人觉得下边效果更好,也不得不佩服TX设计师的聪明才智,让我自己想可能永远也想不到。
至于求 P1P4 和 P2P3 的中点不难吧?连四个坐标点都求出来了,直接算就可以了!
---
源码地址:https://github.com/Xieyupeng520/AZMetaBall(还会不断完善的,求星星^3^)
---
References:
《【Android开源项目解析】QQ“一键下班”功能实现解析——学习Path及贝塞尔曲线的基本使用》
本教程为了方便讲解有篡改原图,还望原图作者见谅!
网友评论
P3.x=startX+cosζ*r,P3.y=startY+sinζ*r //这里的为什么又是相加,为什么不是相减呢?
还请楼主帮忙解释一下吧?
P3.x=startX+cosζ*r,P3.y=startY+sinζ*r //下面的为什么又是加起来,为什么不是相减呢?
还请楼主帮忙解释一下吧?
http://www.jianshu.com/p/dce9794ed07e ,这一篇里面的是match_parent然后设置透明背景来的,那要怎么在item里面设置呢?初学,不懂,谢谢!!!