前言
我们平时在用支付宝付款时,会有一个支付中的动画和一个支付完成的动画。这篇博客主要分析一下这种动画效果,效果如下:
支付宝支付动画
一、动画解析
为了方便观察,放慢了动画的速度并添加辅助线:
放慢后的动画
从图中可以看出:加载圆弧运动轨迹可分为前半段和后半段;并且圆弧的起始角度(startangle)和结束角度(endangle)在做有规律的变化;
前半段: 从-0.5π到π,这一段运动中速度较快;startangle不变,始终未-0.5π;endangle在匀速上升,一直到π;前半段中圆弧不断变长,最后形成一个3/4的圆。
后半段: 从π到1.5π,这一段运动速度较慢;startangle开始变化,从-0.5π变化到1.5π;endangle从π变化到1.5π,最后startangle和endangle重合于1.5π;后半段中圆弧不断变长,最后直至消失。
二、实现代码
1、初始化一些全局属性
1
2
3
4
5
6
7
8
9
10
11
12
|
{ //刷新工具 cadisplaylink *_link; //显示圆环 cashapelayer *_animationlayer; //起始角度 cgfloat _startangle; //结束角度 cgfloat _endangle; //当前动画进度 cgfloat _progress; } |
2、界面刷新工作由cadisplaylink来完成
1
2
3
|
_link = [cadisplaylink displaylinkwithtarget:self selector:@selector(displaylinkaction)]; [_link addtorunloop:[nsrunloop mainrunloop] formode:nsdefaultrunloopmode]; _link.paused = true ; |
为了实现前半段和后半段的速度区别,定义了一个速度方法:
1
2
3
4
5
6
|
-(cgfloat)speed{ if (_endangle > m_pi) { return 0.1/60.0f; } return 0.8/60.0f; } |
通过cadisplaylink刷新进度,进度增长的快慢有speed决定:
1
2
3
4
5
6
7
|
-( void )displaylinkaction{ _progress += [self speed]; if (_progress >= 1) { _progress = 0; } [self updateanimationlayer]; } |
刷新贝塞尔曲线的startangle和endangle实现曲线的运动:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
-( void )updateanimationlayer{ _startangle = -m_pi_2; _endangle = -m_pi_2 +_progress * m_pi * 2; if (_endangle > m_pi) { cgfloat progress1 = 1 - (1 - _progress)/0.25; _startangle = -m_pi_2 + progress1 * m_pi * 2; } cgfloat radius = _animationlayer.bounds.size.width/2.0f - linewidth/2.0f; cgfloat centerx = _animationlayer.bounds.size.width/2.0f; cgfloat centery = _animationlayer.bounds.size.height/2.0f; uibezierpath *path = [uibezierpath bezierpathwitharccenter:cgpointmake(centerx, centery) radius:radius startangle:_startangle endangle:_endangle clockwise: true ]; path.linecapstyle = kcglinecapround; _animationlayer.path = path.cgpath; } |
支付完成动画解析
为了方便观察,放慢了动画的速度,并添加辅助线:
原理分析
通过上图可知,支付完成的动画由两部分组成:圆环动画 + 对号动画
三、代码实现
1、圆环动画
这个动画比较简单,是利用贝塞尔曲线画弧的功能。再利用cashapelayer的strokeend属性加上核心动画实现的圆环动画。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
-( void )circleanimation{ //显示图层 cashapelayer *circlelayer = [cashapelayer layer]; circlelayer.frame = _animationlayer.bounds; [_animationlayer addsublayer:circlelayer]; circlelayer.fillcolor = [[uicolor clearcolor] cgcolor]; circlelayer.strokecolor = bluecolor.cgcolor; circlelayer.linewidth = linewidth; circlelayer.linecap = kcalinecapround; //运动路径 cgfloat linewidth = 5.0f; cgfloat radius = _animationlayer.bounds.size.width/2.0f - linewidth/2.0f; uibezierpath *path = [uibezierpath bezierpathwitharccenter:circlelayer.position radius:radius startangle:-m_pi/2 endangle:m_pi*3/2 clockwise: true ]; circlelayer.path = path.cgpath; //执行动画 cabasicanimation *checkanimation = [cabasicanimation animationwithkeypath:@ "strokeend" ]; checkanimation.duration = circleduriation; checkanimation.fromvalue = @(0.0f); checkanimation.tovalue = @(1.0f); checkanimation.delegate = self; [checkanimation setvalue:@ "checkanimation" forkey:@ "animationname" ]; [circlelayer addanimation:checkanimation forkey:nil]; } |
2、对号动画
对号动画是利用了贝塞尔曲线的画线特性,设置了两段曲线拼接成了一个对号。如上图所示对号由线段ab和线段bc拼接完成,然后再利用核心动画和cashapelayer的strokeend属性实现对号动画。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
-( void )checkanimation{ //外切圆的边长 cgfloat a = _animationlayer.bounds.size.width; //设置三个点 a、b、c uibezierpath *path = [uibezierpath bezierpath]; [path movetopoint:cgpointmake(a*2.7/10,a*5.4/10)]; [path addlinetopoint:cgpointmake(a*4.5/10,a*7/10)]; [path addlinetopoint:cgpointmake(a*7.8/10,a*3.8/10)]; //显示图层 cashapelayer *checklayer = [cashapelayer layer]; checklayer.path = path.cgpath; checklayer.fillcolor = [uicolor clearcolor].cgcolor; checklayer.strokecolor = bluecolor.cgcolor; checklayer.linewidth = linewidth; checklayer.linecap = kcalinecapround; checklayer.linejoin = kcalinejoinround; [_animationlayer addsublayer:checklayer]; //执行动画 cabasicanimation *checkanimation = [cabasicanimation animationwithkeypath:@ "strokeend" ]; checkanimation.duration = checkduration; checkanimation.fromvalue = @(0.0f); checkanimation.tovalue = @(1.0f); checkanimation.delegate = self; [checkanimation setvalue:@ "checkanimation" forkey:@ "animationname" ]; [checklayer addanimation:checkanimation forkey:nil]; } |
源码下载:
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:http://blog.csdn.net/u013282507/article/details/70211889