仿酷狗音乐转场动画
2018-04-26 本文已影响190人
CoderXLL
一、前言
音乐播放器,我一直是用酷狗的。不仅仅是因为她的音乐资源,更主要的是这款App的用户体验--各种流畅的滑动,无比绚烂的UI。其中最让我喜欢的就是她的转场动画了,用起来很顺手。

今天这篇文章先不介绍如何自定义转场动画。我们主要就来玩一下酷狗音乐的转场动画的动画实现。
二、酷狗音乐转场动画初探索,建立数学模型
根据上面的动图,小伙伴们仔细观察酷狗音乐是如何将两个页面进行转场的。其实不难发现A页面过渡到B页面,就是将B页面旋转移动过来的。
其移动的方式大致如下图所示:

如上图,B页面通过动画移动到A页面就是酷狗音乐转场的一个动画实现。很简单,通过视图的transform属性就能够实现。
现在面临的主要问题就是B页面与A页面它的一个位置关系是如何的呢?
针对上面的问题,我们可以从两个方面来回答:
- A页面与B页面有一个角度上的偏移。
这个角度我们可以给个固定值,目测大概25°角。 - 在A沿着右下角旋转25度角后,再沿着垂直边向上方法平移一定距离,可到达B页面。
这个距离我们也可以给个固定值,大概50point(Point为苹果的单位,不熟悉的小伙伴请移步iOS绘制1像素线的正确姿势)
三、计算A,B两个页面的角度偏移量与位置偏移量
- A,B页面的角度偏移量。
以苹果手机左上角为原点坐标,即A页面左上角为原点,B页面的横向与纵向边相对于这个坐标的X轴,Y轴的夹角就是A,B页面的角度偏移量,即25°。 - A,B页面的位置偏移量
我们可以将A,B页面的中心点作为参照点。找到两个页面中心点在X轴与Y轴的距离就是A,B页面的位置偏移量。如图所示:
页面偏移量
如图可见,A页面中心点a与B页面中心点b的位置偏移量即为:垂直方向上偏移量为线段bc的长度,水平方向上偏移量为线段ab的长度
下面我们就来计算线段ab与线段bc的长度
。
一开始我们也说了A页面过渡到B页面,首先是A页面顺时针旋转25°角。如图:
A页面旋转25度至B页面示意图
如图可以看到当前的直角△abc。如果B页面在此基础上再向上平移50point,即B页面中心点b向上平移50point至b'。我们会发现水平方向的偏移量ac不会改变。垂直方向上偏移量bc在大于50point的时候,会减少50point。
平移后的B页面
根据向上平移的多少,b'可能在线段ac的上方或者下方或者acb'三点一线。
所以我们计算出旋转且未上移这种状态下的ac与bc就能够计算出旋转且上移情况下的垂直偏移量与水平偏移量。
假设A页面长宽分别为2x,2y。 - 首先计算当前斜边ab
如图我们做一个辅助线,连接ad,bd
可知abd为等腰三角形,并且可以计算出ad与A页面垂直边的夹角β=arctan(x/y),那么∠adb=β*2+(25.0/180)*PI。ad=sqrt(x*x+y*y)
。由此可得ab=2*ad*sin(β/2.0)
。 - 计算∠cab
先计算∠cad=arctan(y/x)
,再计算∠bad=(PI-∠adb)/2.0。
由此可得∠cab=∠cad-∠bad
。 - 计算横向偏移量ac
因为△abc为直角三角形,所以ac=ab*cos(∠cab)
。 - 计算纵向偏移量bc
bc=ab*sin(∠cab)
四、代码实现
我们知道A,B两个页面的宽高实际上为手机屏幕的宽高。这里要注意一点的就是角度的转换。
- 角度转换公式我用的一个宏定义如下:
// 角度转换
#define angelToRandian(x) ((x)/180.0*M_PI)
- 动画核心算法
CGFloat x = fromView.frame.size.width * 0.5;
CGFloat y = fromView.frame.size.height * 0.5;
//计算边长ab函数
float calculateAB (float x, float y) {
//等腰三角形adb的腰长
float ad = sqrt(pow(x, 2) + pow(y, 2));
//角bda
float bda = atan(x/y)*2+angelToRandian(25);
//角bad
float bad = (M_PI - bda)*0.5;
//边ab
float ab = (ad * cos(bad))*2;
return ab;
}
//计算角cab函数
float calculateCAB (float x, float y) {
//角bda
float bda = atan(x/y)*2+angelToRandian(25);
//角bad
float bad = (M_PI - bda)*0.5;
//角cad
float cad = atan(y/x);
//角cab
float cab = cad-bad;
return cab;
}
//计算ac
CGFloat ac = calculateAB(x, y) * cos(calculateCAB(x, y));
//计算bc
CGFloat bc = calculateAB(x, y) * sin(calculateCAB(x, y));
//最终的横纵向偏移量
CGFloat spacingX = ac;
CGFloat spacingY = 50>bc?50-bc:bc-50;
//设置B页面的初始位置偏移
toView.transform = CGAffineTransformTranslate(toView.transform, spacingX, spacingY);
//设置B页面的初始角度偏移
toView.transform = CGAffineTransformRotate(toView.transform, angelToRandian(25));
//开始动画
[UIView animateWithDuration:3.0 animations:^{
toView.transform = CGAffineTransformIdentity;
}];
动画效果如下:

本篇文章作为一个引子,主要是为下一篇如何实现自定义转场动画作为铺垫。敬请期待。喜欢的小伙伴顺手给个💗,谢谢~