記錄一下最近的動畫實現(xiàn),通過文檔以及調(diào)試的知識tip積累。
1. 組合動畫對象盡量不要保存為全局屬性或者變量。
2.CAKeyframeAnimation .values?以及.keyTimes是一一對應(yīng), keyTimes 的取值是【0~1】,這里是按照時間取值的。
3.CAAnimationGroup 這個動畫組的時間是所有動畫的總時間, 多余的時間會被CAAnimationGroup 的duration裁剪。
NSString * const AnimationKey = @"AnimationKey";
NSString * const TwelveFrameAnimation? ? ? = @"TwelveFrameAnimation";
NSString * const FourteenFrameAnimation? ? = @"FourteenFrameAnimation";
NSString * const EightteenFrameAnimation? ? = @"EightteenFrameAnimation";
NSString * const ThirtyFrameAnimation? ? ? = @"ThirtyFrameAnimation";
NSString * const SixteenFrameAnimation? ? ? = @"SixteenFrameAnimation";
NSString * const CircleImageViewValue? ? ? = @"CircleImageViewValue";
NSString * const FAGuideAnimationXPath? ? ? = @"transform.translation.x";
NSString * const FAGuideAnimationYPath? ? ? = @"transform.translation.y";
NSString * const FAGuideAnimationZPath? ? ? = @"transform.rotation.z";
NSString * const FAGuideAnimationOpacity? ? = @"opacity";
NSString * const FAGuideAnimationPath? ? ? = @"path";
NSInteger const frame = 24.000;
@interface GestureGuideView ()<CAAnimationDelegate>
/// 手勢圖片
@property (nonatomic, strong) UIImageView *handImageView;
@property (nonatomic, strong) CAShapeLayer *radarLayer;
/// 描述
@property (nonatomic, strong) UILabel *desLabel;
@property (nonatomic, copy) void(^complete)(void);
@end
@implementation GestureGuideView
- (instancetype)initWithFrame:(CGRect)frame
{
? ? self = [super initWithFrame:frame];
? ? if (self)
? ? {
? ? ? ? [self addSubview:self.handImageView];
? ? ? ? [self addSubview:self.desLabel];
? ? ? ? self.backgroundColor = [UIColor redColor];
? ? ? ? [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickGesGudieView)]];
? ? }
? ? return self;
}
- (UILabel *)desLabel
{
? ? if (!_desLabel)
? ? {
? ? ? ? _desLabel = [[UILabel alloc] init];
? ? ? ? _desLabel.textColor = HexColor(0xFFFFFF);
? ? ? ? _desLabel.top = self.handImageView.bottom+10.0f;
? ? ? ? _desLabel.width = self.width;
? ? ? ? _desLabel.height = 14.0f;
? ? ? ? _desLabel.textAlignment = NSTextAlignmentCenter;
? ? }
? ? return _desLabel;
}
- (CGFloat)handViewX
{
? ? return self.centerX + 12.0f - self.handImageView.width/2.0f;
}
- (CGFloat)handViewY
{
? ? return self.height/3.0 - self.handImageView.height;
}
- (UIImageView *)handImageView
{
? ? if (!_handImageView)
? ? {
? ? ? ? _handImageView = [[UIImageView alloc] init];
? ? ? ? UIImage *image = FAIMAGE(@"fx_hander_click");
? ? ? ? _handImageView.image = image;
? ? ? ? _handImageView.width = image.size.width;
? ? ? ? _handImageView.height = image.size.height;
? ? ? ? _handImageView.x = [self handViewX];
? ? ? ? _handImageView.y = [self handViewY];
? ? ? ? _handImageView.alpha = 0;
? ? ? ? [self addSubview:_handImageView];
? ? }
? ? return _handImageView;
}
- (CAShapeLayer *)radarLayer
{
? ? if (!_radarLayer)
? ? {
? ? ? ? _radarLayer = [CAShapeLayer layer];
? ? ? ? CGPoint centerPoint = CGPointMake([self handViewX] - 12, [self handViewY] - 18);
? ? ? ? UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:centerPoint
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? radius:10
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? startAngle:0
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? endAngle:2 * M_PI
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clockwise:YES];
? ? ? ? _radarLayer.frame = CGRectMake(centerPoint.x, centerPoint.y, 10, 10);
? ? ? ? _radarLayer.fillColor = [UIColor whiteColor].CGColor;
? ? ? ? _radarLayer.opacity = 0;
? ? ? ? _radarLayer.path = path.CGPath;
? ? ? ? [self.layer insertSublayer:_radarLayer above:0];
? ? }
? ? return _radarLayer;
}
- (void)clickGesGudieView
{
? ? if (self.superview)
? ? {
? ? ? ? [self removeFromSuperview];
? ? ? ? if (self.complete)
? ? ? ? {
? ? ? ? ? ? self.complete();
? ? ? ? }
? ? ? ? [self.handImageView.layer removeAllAnimations];
? ? ? ? [self.radarLayer removeAllAnimations];
? ? }
}
- (void)startAnimation:(void(^)(void))complete
{
? ? self.complete = complete;
? ? [self startAnima];
}
- (void)startAnima
{
? ? self.handImageView.layer.anchorPoint = CGPointMake(0.5, 1);
? ? self.handImageView.layer.position = CGPointMake(self.handImageView.centerX, [self handViewY]+self.handImageView.height);
? ? [self handImageViewAnimation];
}
- (void)shapeLayerAnimation
{
? ? [self.radarLayer addAnimation:[self cicleAnimationGroup:0] forKey:CircleImageViewValue];
? ? [self.radarLayer addAnimation:[self cicleAnimationGroup:4/frame] forKey:CircleImageViewValue];
}
- (void)handImageViewAnimation
{
? ? [NSObject cancelPreviousPerformRequestsWithTarget:self];
? ? [self.handImageView.layer addAnimation:[self twelveFrameAnimation] forKey:TwelveFrameAnimation];
}
- (CAAnimationGroup *)thirtyFrameAnimation
{
? ? CGFloat duration = 12.000/frame;
? ? CAKeyframeAnimation *animationY = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationYPath];
? ? animationY.duration = duration;
? ? animationY.values = @[@(-18.0f),@(0)];
? ? animationY.keyTimes = @[@(0), @(1)];
? ? CAKeyframeAnimation *animationX = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationXPath];
? ? animationX.duration = duration;
? ? animationX.values = @[@(-12.0f), @(0)];
? ? animationX.keyTimes = @[@(0), @(1)];
? ? CAKeyframeAnimation *animationOpacity = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationOpacity];
? ? animationOpacity.duration = duration;
? ? animationOpacity.values = @[@(1), @(0)];
? ? animationOpacity.keyTimes = @[@(0), @(1)];
? ? CAAnimationGroup *group = [CAAnimationGroup animation];
? ? group.animations = @[animationY,animationX, animationOpacity];
? ? group.duration = duration;
? ? group.repeatCount = 1;
? ? group.beginTime = CACurrentMediaTime();
? ? group.delegate = self;
? ? group.fillMode = kCAFillModeForwards;
? ? group.removedOnCompletion = NO;
? ? [group setValue:ThirtyFrameAnimation forKey:AnimationKey];
? ? return group;
}
- (CAKeyframeAnimation *)eightteenFrameAnimation
{
? ? CGFloat duration = 2.000/frame;
? ? CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationZPath];
? ? animation.duration = duration;
? ? animation.beginTime = CACurrentMediaTime();
? ? animation.values = @[@(M_PI/9),@(0)];
? ? animation.keyTimes = @[@(0),@(1)];
? ? animation.fillMode = kCAFillModeForwards;
? ? animation.removedOnCompletion = NO;
? ? animation.delegate = self;
? ? [animation setValue:EightteenFrameAnimation forKey:AnimationKey];
? ? return animation;
}
- (CAKeyframeAnimation *)sixteenFrameAnimation
{
? ? CGFloat duration = 2.000/frame;
? ? CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationZPath];
? ? animation.duration = duration;
? ? animation.beginTime = CACurrentMediaTime();
? ? animation.values = @[@(0),@(M_PI/9)];
? ? animation.keyTimes = @[@(0),@(1)];
? ? animation.fillMode = kCAFillModeForwards;
? ? animation.removedOnCompletion = NO;
? ? [animation setValue:SixteenFrameAnimation forKey:AnimationKey];
? ? animation.delegate = self;
? ? return animation;
}
- (CAKeyframeAnimation *)fourteenFrameAnimation
{
? ? CGFloat duration = 2.000/frame;
? ? CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationZPath];
? ? animation.duration = duration;
? ? animation.beginTime = CACurrentMediaTime();
? ? animation.values = @[@(M_PI/9),@(0)];
? ? animation.keyTimes = @[@(0),@(1)];
? ? animation.fillMode = kCAFillModeForwards;
? ? animation.removedOnCompletion = NO;
? ? animation.delegate = self;
? ? [animation setValue:FourteenFrameAnimation forKey:AnimationKey];
? ? return animation;
}
- (CAAnimationGroup *)twelveFrameAnimation
{
? ? CGFloat duration = 12.000/frame;
? ? CAKeyframeAnimation *rotation = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationZPath];
? ? rotation.duration = duration;
? ? rotation.values = @[@(0),@(M_PI/9)];
? ? rotation.keyTimes = @[@(0),@(1)];
? ? CAKeyframeAnimation *animationY = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationYPath];
? ? animationY.duration = duration;
? ? animationY.values = @[@(0),@(-18.0f)];
? ? animationY.keyTimes = @[@(0), @(1)];
? ? CAKeyframeAnimation *animationX = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationXPath];
? ? animationX.duration = duration;
? ? animationX.values = @[@(0), @(-12.0f)];
? ? animationX.keyTimes = @[@(0), @(1)];
? ? // 透明值
? ? CAKeyframeAnimation *animationOpacity = [CAKeyframeAnimation animationWithKeyPath:FAGuideAnimationOpacity];
? ? animationOpacity.duration = duration;
? ? animationOpacity.values = @[@(0), @(1)];
? ? animationOpacity.keyTimes = @[@(0), @(1)];
? ? CAAnimationGroup *group = [CAAnimationGroup animation];
? ? group.animations = @[rotation,animationY,animationX, animationOpacity];
? ? group.duration = duration;
? ? group.repeatCount = 1;
? ? group.delegate = self;
? ? group.beginTime = CACurrentMediaTime();
? ? group.fillMode = kCAFillModeForwards;
? ? group.removedOnCompletion = NO;
? ? group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
? ? [group setValue:TwelveFrameAnimation forKey:AnimationKey];
? ? return group;
}
- (CAAnimationGroup *)cicleAnimationGroup:(CGFloat)delay
{
? ? CABasicAnimation *basicAnimation = [CABasicAnimation animation];
? ? basicAnimation.keyPath = FAGuideAnimationPath;
? ? CGPoint center = CGPointMake(self.radarLayer.bounds.size.width/2, self.radarLayer.bounds.size.height/2);
? ? UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:center radius:10 startAngle:0 endAngle:2 * M_PI clockwise:YES];
? ? UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:center radius:18 startAngle:0 endAngle:2 * M_PI clockwise:YES];
? ? UIBezierPath *path3 = [UIBezierPath bezierPathWithArcCenter:center radius:25 startAngle:0 endAngle:2 * M_PI clockwise:YES];
? ? basicAnimation.fromValue = (__bridge id _Nullable)(path1.CGPath);
? ? basicAnimation.byValue = (__bridge id _Nullable)(path2.CGPath);
? ? basicAnimation.toValue = (__bridge id _Nullable)(path3.CGPath);
? ? basicAnimation.fillMode = kCAFillModeForwards;
? ? CABasicAnimation *opacityAnimation = [CABasicAnimation animation];
? ? opacityAnimation.keyPath = FAGuideAnimationOpacity;
? ? opacityAnimation.fromValue = @(0.3);
? ? opacityAnimation.toValue = @(0);
? ? opacityAnimation.fillMode = kCAFillModeForwards;
? ? CAAnimationGroup *group = [CAAnimationGroup animation];
? ? group.animations = @[basicAnimation,opacityAnimation];
? ? group.duration = 6.000/frame;
? ? group.beginTime = CACurrentMediaTime() + delay;
? ? group.repeatCount = 1;
? ? group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
? ? group.removedOnCompletion = YES;
? ? return group;
}
#pragma - delegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
? ? if (flag)
? ? {
? ? ? ? NSString *animationName = [NSString stringWithFormat:@"%@",[anim valueForKey:AnimationKey]];
? ? ? ? if ([animationName isEqualToString:ThirtyFrameAnimation])
? ? ? ? {
? ? ? ? ? ? [self performSelector:@selector(handImageViewAnimation) withObject:nil afterDelay:.2];
? ? ? ? }
? ? ? ? else if ([animationName isEqualToString:TwelveFrameAnimation])
? ? ? ? {
? ? ? ? ? ? [self.handImageView.layer addAnimation:[self fourteenFrameAnimation] forKey:FourteenFrameAnimation];
? ? ? ? }
? ? ? ? else if ([animationName isEqualToString:FourteenFrameAnimation])
? ? ? ? {
? ? ? ? ? ? [self.handImageView.layer addAnimation:[self sixteenFrameAnimation] forKey:SixteenFrameAnimation];
? ? ? ? ? ? [self shapeLayerAnimation];
? ? ? ? }
? ? ? ? else if ([animationName isEqualToString:SixteenFrameAnimation])
? ? ? ? {
? ? ? ? ? ? [self.handImageView.layer addAnimation:[self eightteenFrameAnimation] forKey:EightteenFrameAnimation];
? ? ? ? }
? ? ? ? else if ([animationName isEqualToString:EightteenFrameAnimation])
? ? ? ? {
? ? ? ? ? ? [self.handImageView.layer addAnimation:[self thirtyFrameAnimation] forKey:TwelveFrameAnimation];
? ? ? ? ? ? [self shapeLayerAnimation];
? ? ? ? }
? ? }
}