这个动画比较简单基础,首先我们来看一下这个动画模拟的动图
下载动画
动画一共有四个状态,开始下载、下载结束、下载成功和下载失败
为什么会分有下载结束这样的状态呢?因为考虑到实际场景,可能会有在加载过程中,用户返回上级界面,我们需要结束下载动画
我们按状态来实现,首先先看开始加载
CABasicAnimation *rotationZAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationZAnimation.fromValue = @(0);
rotationZAnimation.toValue = @(M_PI*2);
rotationZAnimation.repeatDuration = HUGE_VAL;
rotationZAnimation.duration = 1.0;
rotationZAnimation.cumulative = YES;
rotationZAnimation.beginTime = CACurrentMediaTime();
[self.loadingLayer addAnimation:rotationZAnimation forKey:@"rotationZAnimation"];
NSArray *values = [self valueArrayWithWidth:self.downloadingViewWidth];
CAKeyframeAnimation *boundsAnimation = [self bounsAnimationWithValues:values];
[self.loadingLayer addAnimation:boundsAnimation forKey:nil];
这里分为两个动画,一个是旋转动画,一个是放大缩小的动画
旋转动画,我们只有一个初始值和末值,所以我们只需要使用CABasicAnimation就可以了,不需要使用CAKeyframeAnimation,CAKeyframeAnimation是用来处理关键帧动画的,它的values属性用来存储关键帧的值,这就是我们用来做处理放大缩小动画,上面代码可以看到我将它抽成了一个方法来用,因为在下载成功和失败的时候,成功和失败也是有放大缩小的动画,这三个其实是一个动画
- (NSArray *)valueArrayWithWidth:(CGFloat)width {
return @[[NSValue valueWithCGRect:CGRectMake(0, 0, width * 0.7, width * 0.7)],
[NSValue valueWithCGRect:CGRectMake(0, 0, width, width)],
[NSValue valueWithCGRect:CGRectMake(0, 0, width * 0.9, width * 0.9)]];
}
- (CAKeyframeAnimation *)bounsAnimationWithValues:(NSArray *)values {
CAKeyframeAnimation *boundsAnimation = [CAKeyframeAnimation animationWithKeyPath:@"bounds"];
boundsAnimation.duration = 0.6;
boundsAnimation.beginTime = CACurrentMediaTime();
boundsAnimation.values = values;
boundsAnimation.keyTimes = @[@(0),@(0.3),@(0.6)];
boundsAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
boundsAnimation.removedOnCompletion = NO;
boundsAnimation.fillMode = kCAFillModeForwards;
return boundsAnimation;
}
我们统一设置动画的values值,这里传入的width值是下载的背景大小,因为下载圆圈有个放大的过程,所以我们需要圆圈的原始大小要比背景的大小小,所以我默认设置圆圈的大小是背景大小的0.9倍,所以动画的效果是圆圈从背景大小的0.7倍->背景大小->背景大小的0.9倍(圆圈的原始大小)
在设置这个动画的时候,因为动画的值不止是初始值和末值,还是中间值,所以我使用CAKeyframeAnimation来做,每个关键帧之间的动画时间设置为0.3秒,这是最适合的动画时间,当然这是时间还是由自己反复调试动画决定的
下载结束我们只要将转圈的动画移除掉即可,这样转圈就恢复到原来的状态了
[self.loadingLayer removeAllAnimations];
下载成功我们也需要将转圈动画移除,然后出现成功的动画,并且将成功图层的透明度从0变到1
[self.loadingLayer removeAllAnimations];
self.failLayer.opacity = 0.0;
NSArray *values = [self valueArrayWithWidth:self.downloadingViewWidth * 0.5];
CAKeyframeAnimation *boundsAnimation = [self bounsAnimationWithValues:values];
[self.doneLayer addAnimation:boundsAnimation forKey:nil];
[UIView animateWithDuration:1.0 animations:^{
self.doneLayer.opacity = 1.0;
}];
下载失败也是同理
[self.loadingLayer removeAllAnimations];
self.doneLayer.opacity = 0.0;
NSArray *values = [self valueArrayWithWidth:self.downloadingViewWidth * 0.5];
CAKeyframeAnimation *boundsAnimation = [self bounsAnimationWithValues:values];
[self.failLayer addAnimation:boundsAnimation forKey:nil];
[UIView animateWithDuration:1.0 animations:^{
self.failLayer.opacity = 1.0;
}];
好了,动画主要的原理就是这样,具体的代码实现可以看这里:https://github.com/Yuzeyang/DownloadingAnimation
如果有什么意见或者建议,欢迎大家留言,知识是需要交流的,我相信会有更好更简洁的方法来处理
这个是我的个人微信公众号,会不定期发表一些iOS开发文章以及疑难问题和我在阅读技术和非技术书籍的一些感悟,欢迎大家订阅!
宫城Dev
网友评论