項(xiàng)目中遇到一個(gè)比較有意思的loading動(dòng)畫需求,最終效果如下:
分析
相信很多人跟我一樣第一眼被這張圖欺騙了,以為是有一個(gè)實(shí)心圓在做縮放旋轉(zhuǎn)的動(dòng)畫,其實(shí)仔細(xì)單獨(dú)觀察每個(gè)圓形,不難看出,這個(gè)loading只是由8個(gè)圓形規(guī)律的做放大縮小的動(dòng)畫,同時(shí)加上了透明度的變化達(dá)到了圖中的效果,由此我們有了思路:8個(gè)圓形,scale animate + opacity animate.
代碼實(shí)現(xiàn)
我嘗試使用最基礎(chǔ)的CAAnimation
中api來(lái)完成想要的效果,由之前的思路,我們首先將縮放動(dòng)畫與透明漸變動(dòng)畫實(shí)現(xiàn)出來(lái):
-
縮放.我們可以看出每個(gè)圓形的縮放比例是經(jīng)歷了
1,0.4,1
這三個(gè)階段,當(dāng)然你也可以理解為0.4,1,0.4
,至于為什么是0.4,僅僅是覺(jué)的比較好看Orz,并且我們定義動(dòng)畫完成一個(gè)循環(huán)需要的時(shí)間是1s. -
透明漸變. 每個(gè)圓形的opacity屬性經(jīng)歷了
1,0.3,1
這三個(gè)階段,同上選中0.3,1,0.3
也取決于你的喜好,同樣的一個(gè)循環(huán)時(shí)間為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;
}
接下來(lái)我們使用CAAnimationGroup
來(lái)包裝這兩個(gè)動(dòng)畫:
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;
最后的步驟,按照?qǐng)A形排列繪制8個(gè)原點(diǎn),我們可以使用CAShapeLayer
跟UIBszierPath
結(jié)合來(lái)繪制圓形圖案,代碼都非常簡(jiǎn)單,不做更多解讀了,至于8個(gè)圖形的擺放位置這里可能需要一點(diǎn)高中數(shù)學(xué)知識(shí)了:
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;
}
通常,對(duì)于這種小的動(dòng)畫我習(xí)慣封裝成一個(gè)單獨(dú)的animation類,方便在其他地方調(diào)用,你可以在這里下載到這個(gè)demo.
如有你對(duì)本文有什么好的建議,歡迎提出咯