2014 snapchat source code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
6.9 KiB

  1. //
  2. // SCTapAnimationView.m
  3. // SCCamera
  4. //
  5. // Created by Alexander Grytsiuk on 8/26/15.
  6. // Copyright (c) 2015 Snapchat, Inc. All rights reserved.
  7. //
  8. #import "SCTapAnimationView.h"
  9. #import <SCBase/SCMacros.h>
  10. @import QuartzCore;
  11. static const CGFloat kSCAnimationStep = 0.167;
  12. static const CGFloat kSCInnerCirclePadding = 2.5;
  13. static const CGFloat kSCTapAnimationViewWidth = 55;
  14. static const CGFloat kSCOuterRingBorderWidth = 1;
  15. static NSString *const kSCOpacityAnimationKey = @"opacity";
  16. static NSString *const kSCScaleAnimationKey = @"scale";
  17. @implementation SCTapAnimationView {
  18. CALayer *_outerRing;
  19. CALayer *_innerCircle;
  20. }
  21. #pragma mark Class Methods
  22. + (instancetype)tapAnimationView
  23. {
  24. return [[self alloc] initWithFrame:CGRectMake(0, 0, kSCTapAnimationViewWidth, kSCTapAnimationViewWidth)];
  25. }
  26. #pragma mark Life Cycle
  27. - (instancetype)initWithFrame:(CGRect)frame
  28. {
  29. self = [super initWithFrame:frame];
  30. if (self) {
  31. self.userInteractionEnabled = NO;
  32. _outerRing = [CALayer layer];
  33. _outerRing.backgroundColor = [UIColor clearColor].CGColor;
  34. _outerRing.borderColor = [UIColor whiteColor].CGColor;
  35. _outerRing.borderWidth = kSCOuterRingBorderWidth;
  36. _outerRing.shadowColor = [UIColor blackColor].CGColor;
  37. _outerRing.shadowOpacity = 0.4;
  38. _outerRing.shadowOffset = CGSizeMake(0.5, 0.5);
  39. _outerRing.opacity = 0.0;
  40. _outerRing.frame = self.bounds;
  41. _outerRing.cornerRadius = CGRectGetMidX(_outerRing.bounds);
  42. [self.layer addSublayer:_outerRing];
  43. _innerCircle = [CALayer layer];
  44. _innerCircle.backgroundColor = [UIColor whiteColor].CGColor;
  45. _innerCircle.opacity = 0.0;
  46. _innerCircle.frame = CGRectInset(self.bounds, kSCInnerCirclePadding, kSCInnerCirclePadding);
  47. _innerCircle.cornerRadius = CGRectGetMidX(_innerCircle.bounds);
  48. [self.layer addSublayer:_innerCircle];
  49. }
  50. return self;
  51. }
  52. #pragma mark Public
  53. - (void)showWithCompletion:(SCTapAnimationViewCompletion)completion
  54. {
  55. [_outerRing removeAllAnimations];
  56. [_innerCircle removeAllAnimations];
  57. [CATransaction begin];
  58. [CATransaction setCompletionBlock:^{
  59. if (completion) {
  60. completion(self);
  61. }
  62. }];
  63. [self addOuterRingOpacityAnimation];
  64. [self addOuterRingScaleAnimation];
  65. [self addInnerCircleOpacityAnimation];
  66. [self addInnerCircleScaleAnimation];
  67. [CATransaction commit];
  68. }
  69. #pragma mark Private
  70. - (CAKeyframeAnimation *)keyFrameAnimationWithKeyPath:(NSString *)keyPath
  71. duration:(CGFloat)duration
  72. values:(NSArray *)values
  73. keyTimes:(NSArray *)keyTimes
  74. timingFunctions:(NSArray *)timingFunctions
  75. {
  76. CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
  77. keyframeAnimation.duration = duration;
  78. keyframeAnimation.values = values;
  79. keyframeAnimation.keyTimes = keyTimes;
  80. keyframeAnimation.timingFunctions = timingFunctions;
  81. keyframeAnimation.fillMode = kCAFillModeForwards;
  82. keyframeAnimation.removedOnCompletion = NO;
  83. return keyframeAnimation;
  84. }
  85. - (CABasicAnimation *)animationWithKeyPath:(NSString *)keyPath
  86. duration:(CGFloat)duration
  87. fromValue:(NSValue *)fromValue
  88. toValue:(NSValue *)toValue
  89. timingFunction:(CAMediaTimingFunction *)timingFunction
  90. {
  91. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
  92. animation.duration = duration;
  93. animation.fromValue = fromValue;
  94. animation.toValue = toValue;
  95. animation.timingFunction = timingFunction;
  96. animation.fillMode = kCAFillModeForwards;
  97. animation.removedOnCompletion = NO;
  98. return animation;
  99. }
  100. - (void)addOuterRingOpacityAnimation
  101. {
  102. CAKeyframeAnimation *animation =
  103. [self keyFrameAnimationWithKeyPath:@keypath(_outerRing, opacity)
  104. duration:kSCAnimationStep * 5
  105. values:@[ @0.0, @1.0, @1.0, @0.0 ]
  106. keyTimes:@[ @0.0, @0.2, @0.8, @1.0 ]
  107. timingFunctions:@[
  108. [CAMediaTimingFunction functionWithControlPoints:0.0:0.0:0.0:1.0],
  109. [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
  110. [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
  111. ]];
  112. [_outerRing addAnimation:animation forKey:kSCOpacityAnimationKey];
  113. }
  114. - (void)addOuterRingScaleAnimation
  115. {
  116. CAKeyframeAnimation *animation =
  117. [self keyFrameAnimationWithKeyPath:@keypath(_innerCircle, transform)
  118. duration:kSCAnimationStep * 3
  119. values:@[
  120. [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.50, 0.50, 1.0)],
  121. [NSValue valueWithCATransform3D:CATransform3DIdentity],
  122. [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.83, 0.83, 1.0)],
  123. ]
  124. keyTimes:@[ @0.0, @0.66, @1.0 ]
  125. timingFunctions:@[
  126. [CAMediaTimingFunction functionWithControlPoints:0.0:0.0:0.0:1.0],
  127. [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
  128. ]];
  129. [_outerRing addAnimation:animation forKey:kSCScaleAnimationKey];
  130. }
  131. - (void)addInnerCircleOpacityAnimation
  132. {
  133. CAKeyframeAnimation *animation =
  134. [self keyFrameAnimationWithKeyPath:@keypath(_innerCircle, opacity)
  135. duration:kSCAnimationStep * 3
  136. values:@[ @0.0, @0.40, @0.0 ]
  137. keyTimes:@[ @0.0, @0.33, @1.0 ]
  138. timingFunctions:@[
  139. [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
  140. [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
  141. ]];
  142. [_innerCircle addAnimation:animation forKey:kSCOpacityAnimationKey];
  143. }
  144. - (void)addInnerCircleScaleAnimation
  145. {
  146. CABasicAnimation *animation =
  147. [self animationWithKeyPath:@keypath(_innerCircle, transform)
  148. duration:kSCAnimationStep * 2
  149. fromValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 1.0)]
  150. toValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]
  151. timingFunction:[CAMediaTimingFunction functionWithControlPoints:0.0:0.0:0.0:1.0]];
  152. [_innerCircle addAnimation:animation forKey:kSCScaleAnimationKey];
  153. }
  154. @end