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
178 lines
6.9 KiB
//
|
|
// SCTapAnimationView.m
|
|
// SCCamera
|
|
//
|
|
// Created by Alexander Grytsiuk on 8/26/15.
|
|
// Copyright (c) 2015 Snapchat, Inc. All rights reserved.
|
|
//
|
|
|
|
#import "SCTapAnimationView.h"
|
|
|
|
#import <SCBase/SCMacros.h>
|
|
|
|
@import QuartzCore;
|
|
|
|
static const CGFloat kSCAnimationStep = 0.167;
|
|
static const CGFloat kSCInnerCirclePadding = 2.5;
|
|
static const CGFloat kSCTapAnimationViewWidth = 55;
|
|
static const CGFloat kSCOuterRingBorderWidth = 1;
|
|
|
|
static NSString *const kSCOpacityAnimationKey = @"opacity";
|
|
static NSString *const kSCScaleAnimationKey = @"scale";
|
|
|
|
@implementation SCTapAnimationView {
|
|
CALayer *_outerRing;
|
|
CALayer *_innerCircle;
|
|
}
|
|
|
|
#pragma mark Class Methods
|
|
|
|
+ (instancetype)tapAnimationView
|
|
{
|
|
return [[self alloc] initWithFrame:CGRectMake(0, 0, kSCTapAnimationViewWidth, kSCTapAnimationViewWidth)];
|
|
}
|
|
|
|
#pragma mark Life Cycle
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
{
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
self.userInteractionEnabled = NO;
|
|
_outerRing = [CALayer layer];
|
|
_outerRing.backgroundColor = [UIColor clearColor].CGColor;
|
|
_outerRing.borderColor = [UIColor whiteColor].CGColor;
|
|
_outerRing.borderWidth = kSCOuterRingBorderWidth;
|
|
_outerRing.shadowColor = [UIColor blackColor].CGColor;
|
|
_outerRing.shadowOpacity = 0.4;
|
|
_outerRing.shadowOffset = CGSizeMake(0.5, 0.5);
|
|
_outerRing.opacity = 0.0;
|
|
_outerRing.frame = self.bounds;
|
|
_outerRing.cornerRadius = CGRectGetMidX(_outerRing.bounds);
|
|
[self.layer addSublayer:_outerRing];
|
|
|
|
_innerCircle = [CALayer layer];
|
|
_innerCircle.backgroundColor = [UIColor whiteColor].CGColor;
|
|
_innerCircle.opacity = 0.0;
|
|
_innerCircle.frame = CGRectInset(self.bounds, kSCInnerCirclePadding, kSCInnerCirclePadding);
|
|
_innerCircle.cornerRadius = CGRectGetMidX(_innerCircle.bounds);
|
|
[self.layer addSublayer:_innerCircle];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
#pragma mark Public
|
|
|
|
- (void)showWithCompletion:(SCTapAnimationViewCompletion)completion
|
|
{
|
|
[_outerRing removeAllAnimations];
|
|
[_innerCircle removeAllAnimations];
|
|
|
|
[CATransaction begin];
|
|
[CATransaction setCompletionBlock:^{
|
|
if (completion) {
|
|
completion(self);
|
|
}
|
|
}];
|
|
[self addOuterRingOpacityAnimation];
|
|
[self addOuterRingScaleAnimation];
|
|
[self addInnerCircleOpacityAnimation];
|
|
[self addInnerCircleScaleAnimation];
|
|
[CATransaction commit];
|
|
}
|
|
|
|
#pragma mark Private
|
|
|
|
- (CAKeyframeAnimation *)keyFrameAnimationWithKeyPath:(NSString *)keyPath
|
|
duration:(CGFloat)duration
|
|
values:(NSArray *)values
|
|
keyTimes:(NSArray *)keyTimes
|
|
timingFunctions:(NSArray *)timingFunctions
|
|
{
|
|
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:keyPath];
|
|
keyframeAnimation.duration = duration;
|
|
keyframeAnimation.values = values;
|
|
keyframeAnimation.keyTimes = keyTimes;
|
|
keyframeAnimation.timingFunctions = timingFunctions;
|
|
keyframeAnimation.fillMode = kCAFillModeForwards;
|
|
keyframeAnimation.removedOnCompletion = NO;
|
|
|
|
return keyframeAnimation;
|
|
}
|
|
|
|
- (CABasicAnimation *)animationWithKeyPath:(NSString *)keyPath
|
|
duration:(CGFloat)duration
|
|
fromValue:(NSValue *)fromValue
|
|
toValue:(NSValue *)toValue
|
|
timingFunction:(CAMediaTimingFunction *)timingFunction
|
|
{
|
|
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
|
|
animation.duration = duration;
|
|
animation.fromValue = fromValue;
|
|
animation.toValue = toValue;
|
|
animation.timingFunction = timingFunction;
|
|
animation.fillMode = kCAFillModeForwards;
|
|
animation.removedOnCompletion = NO;
|
|
|
|
return animation;
|
|
}
|
|
|
|
- (void)addOuterRingOpacityAnimation
|
|
{
|
|
CAKeyframeAnimation *animation =
|
|
[self keyFrameAnimationWithKeyPath:@keypath(_outerRing, opacity)
|
|
duration:kSCAnimationStep * 5
|
|
values:@[ @0.0, @1.0, @1.0, @0.0 ]
|
|
keyTimes:@[ @0.0, @0.2, @0.8, @1.0 ]
|
|
timingFunctions:@[
|
|
[CAMediaTimingFunction functionWithControlPoints:0.0:0.0:0.0:1.0],
|
|
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
|
|
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
|
|
]];
|
|
[_outerRing addAnimation:animation forKey:kSCOpacityAnimationKey];
|
|
}
|
|
|
|
- (void)addOuterRingScaleAnimation
|
|
{
|
|
CAKeyframeAnimation *animation =
|
|
[self keyFrameAnimationWithKeyPath:@keypath(_innerCircle, transform)
|
|
duration:kSCAnimationStep * 3
|
|
values:@[
|
|
[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.50, 0.50, 1.0)],
|
|
[NSValue valueWithCATransform3D:CATransform3DIdentity],
|
|
[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.83, 0.83, 1.0)],
|
|
]
|
|
keyTimes:@[ @0.0, @0.66, @1.0 ]
|
|
timingFunctions:@[
|
|
[CAMediaTimingFunction functionWithControlPoints:0.0:0.0:0.0:1.0],
|
|
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
|
|
]];
|
|
[_outerRing addAnimation:animation forKey:kSCScaleAnimationKey];
|
|
}
|
|
|
|
- (void)addInnerCircleOpacityAnimation
|
|
{
|
|
CAKeyframeAnimation *animation =
|
|
[self keyFrameAnimationWithKeyPath:@keypath(_innerCircle, opacity)
|
|
duration:kSCAnimationStep * 3
|
|
values:@[ @0.0, @0.40, @0.0 ]
|
|
keyTimes:@[ @0.0, @0.33, @1.0 ]
|
|
timingFunctions:@[
|
|
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
|
|
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
|
|
]];
|
|
[_innerCircle addAnimation:animation forKey:kSCOpacityAnimationKey];
|
|
}
|
|
|
|
- (void)addInnerCircleScaleAnimation
|
|
{
|
|
CABasicAnimation *animation =
|
|
[self animationWithKeyPath:@keypath(_innerCircle, transform)
|
|
duration:kSCAnimationStep * 2
|
|
fromValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0, 0.0, 1.0)]
|
|
toValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]
|
|
timingFunction:[CAMediaTimingFunction functionWithControlPoints:0.0:0.0:0.0:1.0]];
|
|
[_innerCircle addAnimation:animation forKey:kSCScaleAnimationKey];
|
|
}
|
|
|
|
@end
|