SVIndefiniteAnimatedView.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. //
  2. // SVIndefiniteAnimatedView.m
  3. // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
  4. //
  5. // Copyright (c) 2014-2018 Guillaume Campagna. All rights reserved.
  6. //
  7. #import "SVIndefiniteAnimatedView.h"
  8. #import "SVProgressHUD.h"
  9. @interface SVIndefiniteAnimatedView ()
  10. @property (nonatomic, strong) CAShapeLayer *indefiniteAnimatedLayer;
  11. @end
  12. @implementation SVIndefiniteAnimatedView
  13. - (void)willMoveToSuperview:(UIView*)newSuperview {
  14. if (newSuperview) {
  15. [self layoutAnimatedLayer];
  16. } else {
  17. [_indefiniteAnimatedLayer removeFromSuperlayer];
  18. _indefiniteAnimatedLayer = nil;
  19. }
  20. }
  21. - (void)layoutAnimatedLayer {
  22. CALayer *layer = self.indefiniteAnimatedLayer;
  23. [self.layer addSublayer:layer];
  24. CGFloat widthDiff = CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds);
  25. CGFloat heightDiff = CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds);
  26. layer.position = CGPointMake(CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds) / 2 - widthDiff / 2, CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds) / 2 - heightDiff / 2);
  27. }
  28. - (CAShapeLayer*)indefiniteAnimatedLayer {
  29. if(!_indefiniteAnimatedLayer) {
  30. CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5);
  31. UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:self.radius startAngle:(CGFloat) (M_PI*3/2) endAngle:(CGFloat) (M_PI/2+M_PI*5) clockwise:YES];
  32. _indefiniteAnimatedLayer = [CAShapeLayer layer];
  33. _indefiniteAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale];
  34. _indefiniteAnimatedLayer.frame = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2);
  35. _indefiniteAnimatedLayer.fillColor = [UIColor clearColor].CGColor;
  36. _indefiniteAnimatedLayer.strokeColor = self.strokeColor.CGColor;
  37. _indefiniteAnimatedLayer.lineWidth = self.strokeThickness;
  38. _indefiniteAnimatedLayer.lineCap = kCALineCapRound;
  39. _indefiniteAnimatedLayer.lineJoin = kCALineJoinBevel;
  40. _indefiniteAnimatedLayer.path = smoothedPath.CGPath;
  41. CALayer *maskLayer = [CALayer layer];
  42. NSBundle *bundle = [NSBundle bundleForClass:[SVProgressHUD class]];
  43. NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"];
  44. NSBundle *imageBundle = [NSBundle bundleWithURL:url];
  45. NSString *path = [imageBundle pathForResource:@"angle-mask" ofType:@"png"];
  46. maskLayer.contents = (__bridge id)[[UIImage imageWithContentsOfFile:path] CGImage];
  47. maskLayer.frame = _indefiniteAnimatedLayer.bounds;
  48. _indefiniteAnimatedLayer.mask = maskLayer;
  49. NSTimeInterval animationDuration = 1;
  50. CAMediaTimingFunction *linearCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  51. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
  52. animation.fromValue = (id) 0;
  53. animation.toValue = @(M_PI*2);
  54. animation.duration = animationDuration;
  55. animation.timingFunction = linearCurve;
  56. animation.removedOnCompletion = NO;
  57. animation.repeatCount = INFINITY;
  58. animation.fillMode = kCAFillModeForwards;
  59. animation.autoreverses = NO;
  60. [_indefiniteAnimatedLayer.mask addAnimation:animation forKey:@"rotate"];
  61. CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
  62. animationGroup.duration = animationDuration;
  63. animationGroup.repeatCount = INFINITY;
  64. animationGroup.removedOnCompletion = NO;
  65. animationGroup.timingFunction = linearCurve;
  66. CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
  67. strokeStartAnimation.fromValue = @0.015;
  68. strokeStartAnimation.toValue = @0.515;
  69. CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  70. strokeEndAnimation.fromValue = @0.485;
  71. strokeEndAnimation.toValue = @0.985;
  72. animationGroup.animations = @[strokeStartAnimation, strokeEndAnimation];
  73. [_indefiniteAnimatedLayer addAnimation:animationGroup forKey:@"progress"];
  74. }
  75. return _indefiniteAnimatedLayer;
  76. }
  77. - (void)setFrame:(CGRect)frame {
  78. if(!CGRectEqualToRect(frame, super.frame)) {
  79. [super setFrame:frame];
  80. if(self.superview) {
  81. [self layoutAnimatedLayer];
  82. }
  83. }
  84. }
  85. - (void)setRadius:(CGFloat)radius {
  86. if(radius != _radius) {
  87. _radius = radius;
  88. [_indefiniteAnimatedLayer removeFromSuperlayer];
  89. _indefiniteAnimatedLayer = nil;
  90. if(self.superview) {
  91. [self layoutAnimatedLayer];
  92. }
  93. }
  94. }
  95. - (void)setStrokeColor:(UIColor*)strokeColor {
  96. _strokeColor = strokeColor;
  97. _indefiniteAnimatedLayer.strokeColor = strokeColor.CGColor;
  98. }
  99. - (void)setStrokeThickness:(CGFloat)strokeThickness {
  100. _strokeThickness = strokeThickness;
  101. _indefiniteAnimatedLayer.lineWidth = _strokeThickness;
  102. }
  103. - (CGSize)sizeThatFits:(CGSize)size {
  104. return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2);
  105. }
  106. @end