类似图中右下角的气泡抖动效果在app中非常常见,刚好最近项目有这种需求,于是就花了点时间实现了一下,下面讲解一下思路:
动画最重要的是将动作拆分:
这种气泡动画我拆分为两种动画,组成一个动画组:
1.scale动画,即改变视图的尺寸
2.平移动画,也即改变视图的中心y值
动画用到的技术是关键帧动画:
scale动画:
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
NSValue *value1 = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, -10, 0)];
NSValue *value2 = [NSValue valueWithCATransform3D:CATransform3DIdentity];
NSValue *value3 = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, 10, 0)];
NSValue *value4 = [NSValue valueWithCATransform3D:CATransform3DIdentity];
positionAnimation.values = @[value1,value2,value3,value4];
translation动画:
CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
NSValue *scaleValue1 = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 0)];
NSValue *scaleValue2 = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9, 0.9, 0)];
NSValue *scaleValue3 = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 0)];
NSValue *scaleValue4 = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 0)];
scaleAnimation.values = @[scaleValue1,scaleValue2,scaleValue3,scaleValue4];
将这两个动画设置到一个动画组中:
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[positionAnimation,scaleAnimation];
animationGroup.duration = 1.0;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.removedOnCompletion = NO;
animationGroup.repeatCount = 0;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[self.layer addAnimation:animationGroup forKey:@"animation"];
如此就已经完成了,值得一提的是:有的需求可能不是两种动画同时执行,这个时候就可以对单独动画进行设置起始时间,另外,需要注意的是要设置好animationGroup中总的动画时间,笔者在实现功能的时候顺便试了下这种情况发现的。
此外,气泡的画法,下面一并给出:
- (UIImage *)drawBubbleImage {
UIImage *bubbleImage;
UIGraphicsBeginImageContextWithOptions(self.frame.size,NO, [UIScreen mainScreen].scale);
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPath];
path.lineJoinStyle = kCGLineJoinRound;
[path moveToPoint:CGPointMake(0, 5)];
[path addQuadCurveToPoint:CGPointMake(5, 0) controlPoint:CGPointMake(0, 0)];
[path addLineToPoint:CGPointMake(self.frame.size.width - 5, 0)];
[path addQuadCurveToPoint:CGPointMake(self.frame.size.width, 5) controlPoint:CGPointMake(self.frame.size.width, 0)];
[path addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height - 5 - 5)];
[path addQuadCurveToPoint:CGPointMake(self.frame.size.width - 5, self.frame.size.height - 5) controlPoint:CGPointMake(self.frame.size.width, self.frame.size.height - 5)];
[path addLineToPoint:CGPointMake(self.frame.size.width * 0.5 + 5, self.frame.size.height - 5)];
[path addLineToPoint:CGPointMake(self.frame.size.width * 0.5, self.frame.size.height)];
[path addLineToPoint:CGPointMake(self.frame.size.width * 0.5 - 5, self.frame.size.height - 5)];
[path addLineToPoint:CGPointMake(5, self.frame.size.height - 5)];
[path addQuadCurveToPoint:CGPointMake(0, self.frame.size.height - 5 - 5) controlPoint:CGPointMake(0, self.frame.size.height - 5)];
[path closePath];
[self.backImageColor setFill];
CGContextAddPath(ctx, path.CGPath);
CGContextFillPath(ctx);
bubbleImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return bubbleImage;
}