layout: post
title: "Nice 标签动画分析"
date: 2015-04-05 16:51:25 +0800
comments: true
categories: iOS 动画
上图是模仿nice中的标签,接下来分析构建这个控件的过程。
开始需要看下iOS的显示动画 以及 CAAnimationGroup
1. 中间icon的放大缩小动画
首先给layer设置image icon,
layer.contents = (__bridge id)(icon.CGImage);
通过 “transform.scale”这个keypath 来收缩layer,缩放过程如下:
1 缩小到0.8倍
2 放大到1.2倍
3 复原到1.0倍
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = @1;
animation.toValue = @0.8;
animation.duration = 0.2;
CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation1.fromValue = @0.8;
animation1.toValue = @1.2;
animation1.duration = 0.4;
animation1.beginTime = animation.duration;
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation2.fromValue = @1.2;
animation2.toValue = @1;
animation2.duration = 0.2;
animation2.beginTime = animation.duration + animation1.duration;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration = animation.duration + animation1.duration + animation2.duration + 0.1;
animationGroup.repeatCount = 0;
animationGroup.delegate = self;
animationGroup.animations = @[animation,animation1,animation2];
[animationGroup setValue:@"icon" forKey:@"animationName"];
```
CAAnimationGroup中的动画都是并发执行的,所以icon动画关键是通过beginTime设置每个动画开始播放的时间,repeatCount=0,所有动画都为单次播放。
## 2. 脉冲动画
```objc
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation3.fromValue = @0.0;
animation3.toValue = @1.0;
animation3.duration = duration;
//关键帧动画
CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
animation4.duration =duration ;
animation4.values = @[@0.8, @0.45, @0];
animation4.keyTimes = @[@0, @0.2, @1];
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
.......
[animationGroup setValue:@"pulse" forKey:@"animationName"];
```
通过CAAnimationGroup来实现layer一边放大,一边设置透明度来实现脉冲效果,
## 3. 通过Animation的delegate来组合动画
看图是整个动画是由 一个收缩动画 两个脉冲动画组合起来的,组合过程就是由各个CAAnimationGroup的delegate来合成的
```objc
- (void)animationDidStart:(CAAnimation *)animation{ //等第一个脉冲动画播放到0.5秒,开始播放第二个动画
NSString *animationName = [animation valueForKey:@"animationName"];
if ([animationName isEqualToString:@"pulse"]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * self.pulsingGroup.duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[pulsingLayer1 addAnimation:pulsingGroup1 forKey:@"pulse1"];
});
}
}
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished{
NSString *animationName = [animation valueForKey:@"animationName"];
if ([animationName isEqualToString:@"icon"]) { //icon动画播放完结束后添加脉冲动画
[imageLayer removeAnimationForKey:@"icon"];
[pulsingLayer addAnimation:pulsingGroup forKey:@"pulse"];
}else if ([animationName isEqualToString:@"pulse"]){ //第一个脉冲动画播放完成后移除
[pulsingLayer removeAnimationForKey:@"pulse"];
}else if ([animationName isEqualToString:@"pulse1"]){//第二个脉冲动画播放后,再开始循环播放icon动画
[pulsingLayer1 removeAnimationForKey:@"pulse1"];
[imageLayer addAnimation:iconGroup forKey:@"icon"];
}
}
4. 绘制箭头
首先计算tag上文字的宽度加上 除去文字的其他宽度,算出tag的宽度, 然后找到这个箭头的5个角, 通过addArcWithCenter 这个方法 (在每个角上画上一个圆,确定每个圆的半径、圆心以及角度。) 分别在5个角上画5段弧线。然后 使用 [path fill]来填充背景颜色。
5. 绘制文字
NSDictionary *attributes = @{
NSShadowAttributeName : shadow,
NSForegroundColorAttributeName : [UIColor colorWithRed:255 green:255 blue:255 alpha:1],
NSFontAttributeName : [UIFont systemFontOfSize:14]
};
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
[attributedText drawInRect:CGRectMake(0,0,100,height)]
总结
整个控件的动画都是由CAAnimationGroup的delegate调度的,每个CAAnimationGroup完成后,继续另外一个动画。 绘制箭头的时候比较麻烦的是确定每个圆角的角度、半径与圆点,最好在Photoshop或者Sketch上确定好。
在使用过程中,有可能需要需要缩小,这个时候可以通过view的矩阵变换 transform CGAffineTransformMakeScale 来设置大小。
点击下载Demo