项目中遇到一个比较有意思的loading动画需求,最终效果如下:
相信很多人跟我一样第一眼被这张图欺骗了,以为是有一个实心圆在做缩放旋转的动画,其实仔细单独观察每个圆形,不难看出,这个loading只是由8个圆形规律的做放大缩小的动画,同时加上了透明度的变化达到了图中的效果,由此我们有了思路:8个圆形,scale animate + opacity animate.
我尝试使用最基础的 CAAnimation
中api来完成想要的效果,由之前的思路,我们首先将缩放动画与透明渐变动画实现出来:
1,0.4,1
这三个阶段,当然你也可以理解为 0.4,1,0.4
,至于为什么是0.4,仅仅是觉的比较好看Orz,并且我们定义动画完成一个循环需要的时间是1s. 1,0.3,1
这三个阶段,同上选中 0.3,1,0.3
也取决于你的喜好,同样的一个循环时间为1s. //scale - (CAKeyframeAnimation *)scaleAnimation { CAKeyframeAnimation *scaleAnimate = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; scaleAnimate.keyTimes = @[@0, @0.5, @1]; scaleAnimate.values = @[@1, @0.4, @1]; scaleAnimate.duration = kDuration; return scaleAnimate; } //opactity - (CAKeyframeAnimation *)opactityAnimation { CAKeyframeAnimation *opacityAnimaton = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; opacityAnimaton.keyTimes = @[@0, @0.5, @1]; opacityAnimaton.values = @[@1, @0.3, @1]; opacityAnimaton.duration = kDuration; return opacityAnimaton; }
接下来我们使用 CAAnimationGroup
来包装这两个动画:
CAAnimationGroup *animation = [[CAAnimationGroup alloc] init]; animation.animations = @[[self scaleAnimation], [self opactityAnimation]]; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; animation.duration = 1.f; animation.repeatCount = HUGE; animation.removedOnCompletion = NO;
最后的步骤,按照圆形排列绘制8个原点,我们可以使用 CAShapeLayer
跟 UIBszierPath
结合来绘制圆形图案,代码都非常简单,不做更多解读了,至于8个图形的摆放位置这里可能需要一点高中数学知识了:
for (int i = 0; i < 8; i++) { CALayer *circle = [self circleLayerWithAngle:M_PI_4 * i size:circleSize origin:CGPointMake(x, y) containerSize:size color:tintColor]; animation.beginTime = beginTime + i * 0.12; [circle addAnimation:animation forKey:@"animation"]; [layer addSublayer:circle]; } - (CALayer *)circleLayerWithAngle:(CGFloat)angle size:(CGFloat)size origin:(CGPoint)origin containerSize:(CGSize)containerSize color:(UIColor *)color{ CGFloat raduis = containerSize.width * 0.5; CAShapeLayer *layer = [CAShapeLayer layer]; UIBezierPath *path = [[UIBezierPath alloc] init]; [path addArcWithCenter:CGPointMake(size * 0.5, size * 0.5) radius:size * 0.5 startAngle:0 endAngle:M_PI * 2 clockwise:NO]; [path closePath]; layer.fillColor = color.CGColor; layer.path = path.CGPath; CGRect frame = CGRectMake(origin.x + raduis * (cos(angle) + 1), origin.y + raduis * (sin(angle) + 1), size, size); layer.frame = frame; return layer; }
通常,对于这种小的动画我习惯封装成一个单独的animation类,方便在其他地方调用,你可以在 这里 下载到这个demo.
如有更好建议,欢迎提出咯
ps:为什么博客上传完gif的显示位置偏到姥姥家去了o.o