平时在用支付宝付款时,会有一个支付中的动画和一个支付完成的动画。这篇博客主要分析一下 支付中 的动画效果,效果如下:

动画解析-支付宝支付动画 - 图1

一、动画解析

为了方便观察,放慢了动画的速度并添加辅助线:

动画解析-支付宝支付动画 - 图2

从图中可以看出:加载圆弧运动轨迹可分为前半段后半段;并且圆弧的起始角度(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. CADisplayLink *_link;
  4. //显示圆环
  5. CAShapeLayer *_animationLayer;
  6. //起始角度
  7. CGFloat _startAngle;
  8. //结束角度
  9. CGFloat _endAngle;
  10. //当前动画进度
  11. CGFloat _progress;
  12. }

2、界面刷新工作由CADisplayLink来完成

  1. _link = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkAction)];
  2. [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
  3. _link.paused = true;

为了实现前半段后半段的速度区别,定义了一个速度方法:

  1. -(CGFloat)speed{
  2. if (_endAngle > M_PI) {
  3. return 0.1/60.0f;
  4. }
  5. return 0.8/60.0f;
  6. }

通过CADisplayLink刷新进度,进度增长的快慢有speed决定:

  1. -(void)displayLinkAction{
  2. _progress += [self speed];
  3. if (_progress >= 1) {
  4. _progress = 0;
  5. }
  6. [self updateAnimationLayer];
  7. }

刷新贝塞尔曲线的StartAngle和EndAngle实现曲线的运动:

  1. -(void)updateAnimationLayer{
  2. _startAngle = -M_PI_2;
  3. _endAngle = -M_PI_2 +_progress * M_PI * 2;
  4. if (_endAngle > M_PI) {
  5. CGFloat progress1 = 1 - (1 - _progress)/0.25;
  6. _startAngle = -M_PI_2 + progress1 * M_PI * 2;
  7. }
  8. CGFloat radius = _animationLayer.bounds.size.width/2.0f - lineWidth/2.0f;
  9. CGFloat centerX = _animationLayer.bounds.size.width/2.0f;
  10. CGFloat centerY = _animationLayer.bounds.size.height/2.0f;
  11. UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(centerX, centerY) radius:radius startAngle:_startAngle endAngle:_endAngle clockwise:true];
  12. path.lineCapStyle = kCGLineCapRound;
  13. _animationLayer.path = path.CGPath;
  14. }

Github

上一篇博客分析了支付中动画的实现,本篇博客是分析支付完成的动画。

动画解析-支付宝支付动画 - 图3

一、动画解析

为了方便观察,放慢了动画的速度,并添加辅助线:
动画解析-支付宝支付动画 - 图4

通过上图可知,支付完成的动画由两部分组成:圆环动画 + 对号动画

二、代码实现

1、圆环动画

这个动画比较简单,是利用贝塞尔曲线画弧的功能。再利用CAShapeLayer的strokeEnd属性加上核心动画实现的圆环动画。

  1. -(void)circleAnimation{
  2. //显示图层
  3. CAShapeLayer *circleLayer = [CAShapeLayer layer];
  4. circleLayer.frame = _animationLayer.bounds;
  5. [_animationLayer addSublayer:circleLayer];
  6. circleLayer.fillColor = [[UIColor clearColor] CGColor];
  7. circleLayer.strokeColor = BlueColor.CGColor;
  8. circleLayer.lineWidth = lineWidth;
  9. circleLayer.lineCap = kCALineCapRound;
  10. //运动路径
  11. CGFloat lineWidth = 5.0f;
  12. CGFloat radius = _animationLayer.bounds.size.width/2.0f - lineWidth/2.0f;
  13. UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:circleLayer.position radius:radius startAngle:-M_PI/2 endAngle:M_PI*3/2 clockwise:true];
  14. circleLayer.path = path.CGPath;
  15. //执行动画
  16. CABasicAnimation *checkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  17. checkAnimation.duration = circleDuriation;
  18. checkAnimation.fromValue = @(0.0f);
  19. checkAnimation.toValue = @(1.0f);
  20. checkAnimation.delegate = self;
  21. [checkAnimation setValue:@"checkAnimation" forKey:@"animationName"];
  22. [circleLayer addAnimation:checkAnimation forKey:nil];
  23. }

2、对号动画

对号动画是利用了贝塞尔曲线的画线特性,设置了两段曲线拼接成了一个对号。如上图所示对号由线段AB和线段BC拼接完成,然后再利用核心动画和CAShapeLayer的strokeEnd属性实现对号动画。

  1. -(void)checkAnimation{
  2. //外切圆的边长
  3. CGFloat a = _animationLayer.bounds.size.width;
  4. //设置三个点 A、B、C
  5. UIBezierPath *path = [UIBezierPath bezierPath];
  6. [path moveToPoint:CGPointMake(a*2.7/10,a*5.4/10)];
  7. [path addLineToPoint:CGPointMake(a*4.5/10,a*7/10)];
  8. [path addLineToPoint:CGPointMake(a*7.8/10,a*3.8/10)];
  9. //显示图层
  10. CAShapeLayer *checkLayer = [CAShapeLayer layer];
  11. checkLayer.path = path.CGPath;
  12. checkLayer.fillColor = [UIColor clearColor].CGColor;
  13. checkLayer.strokeColor = BlueColor.CGColor;
  14. checkLayer.lineWidth = lineWidth;
  15. checkLayer.lineCap = kCALineCapRound;
  16. checkLayer.lineJoin = kCALineJoinRound;
  17. [_animationLayer addSublayer:checkLayer];
  18. //执行动画
  19. CABasicAnimation *checkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  20. checkAnimation.duration = checkDuration;
  21. checkAnimation.fromValue = @(0.0f);
  22. checkAnimation.toValue = @(1.0f);
  23. checkAnimation.delegate = self;
  24. [checkAnimation setValue:@"checkAnimation" forKey:@"animationName"];
  25. [checkLayer addAnimation:checkAnimation forKey:nil];
  26. }

Github