今天動畫的主要用CAShapeLayer和貝塞爾曲線做一個(gè)提交的動畫谭跨,也是沒有什么難度的
先簡單的介紹下CAShapeLayer
- CAShapeLayer繼承自CALayer,可使用CALayer的所有屬性
- CAShapeLayer需要和貝塞爾曲線配合使用才有意義让簿。
Shape:形狀,貝塞爾曲線可以為其提供形狀检吆,而單獨(dú)使用CAShapeLayer是沒有任何意義的种玛。 - 使用CAShapeLayer與貝塞爾曲線可以實(shí)現(xiàn)不在view的DrawRect方法中畫出一些想要的圖形
關(guān)于CAShapeLayer和DrawRect的比較
DrawRect:DrawRect屬于CoreGraphic框架笑窜,占用CPU致燥,消耗性能大
CAShapeLayer:CAShapeLayer屬于CoreAnimation框架,通過GPU來渲染圖形怖侦,節(jié)省性能篡悟。動畫渲染直接提交給手機(jī)GPU,不消耗內(nèi)存
貝塞爾曲線與CAShapeLayer的關(guān)系
- CAShapeLayer中shape代表形狀的意思匾寝,所以需要形狀才能生效
- 貝塞爾曲線可以創(chuàng)建基于矢量的路徑
- 貝塞爾曲線給CAShapeLayer提供路徑搬葬,CAShapeLayer在提供的路徑中進(jìn)行渲染。路徑會閉環(huán)艳悔,所以繪制出了Shape
- 用于CAShapeLayer的貝塞爾曲線作為Path急凰,其path是一個(gè)首尾相接的閉環(huán)的曲線,即使該貝塞爾曲線不是一個(gè)閉環(huán)的曲線
以上文字來源于網(wǎng)絡(luò)猜年,哈哈
如果有同學(xué)對UIBezierPath不熟悉的請看這里
CAShapeLayer的介紹
上面的介紹也說了貝塞爾曲線給CAShapeLayer提供路徑抡锈,CAShapeLayer在提供的路徑中進(jìn)行渲染,把路徑用以形狀的形式展示出來乔外,CAShapeLayer最重要的屬性就是下面三個(gè):
//動畫的路徑
@property(nullable) CGPathRef path;
//描述path路徑從哪里開始
@property CGFloat strokeStart;
//描述path路徑從哪里結(jié)束
@property CGFloat strokeEnd;
這兩個(gè)值的范圍是[0,1]床三,
接下來我們先畫一個(gè)不會動的 對號 來學(xué)習(xí)一下 CAShapeLayer
UIBezierPath *bezierPath=[UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(self.frame.size.width/4, self.frame.size.height/2)];
[bezierPath addLineToPoint:CGPointMake(self.frame.size.width/2, self.frame.size.height/4*3)];
[bezierPath addLineToPoint:CGPointMake(self.frame.size.width/4*3, self.frame.size.height/3)];
CAShapeLayer *shape=[CAShapeLayer layer];
shape.lineWidth=17;
shape.fillColor=[UIColor clearColor].CGColor;
shape.strokeColor=[UIColor colorWithRed:0.76f green:0.89f blue:0.89f alpha:1.00f].CGColor;
shape.lineCap = kCALineCapRound;
shape.lineJoin = kCALineJoinRound;
shape.path=bezierPath.CGPath;
[self.layer addSublayer:shape];
UIBezierPath只是告訴路徑給CAShapeLayer杨幼,具體這個(gè)shape什么樣子由CAShapeLayer來決定
所以一些屬于lineWidth撇簿,fillColor是在shape上設(shè)置的,在UIBezierPath上設(shè)置無效
補(bǔ)充:lineCap
- kCALineCapButt: 默認(rèn)格式差购,不附加任何形狀;
- kCALineCapRound: 在線段頭尾添加半徑為線段 lineWidth 一半的半圓四瘫;
- kCALineCapSquare: 在線段頭尾添加半徑為線段 lineWidth 一半的矩形”
CAShapeLayer的基本用法就是這樣接下來就是動畫了
動畫第一步長方形變圓形
先添加一個(gè)checkButton的cornerRadius變?yōu)閳A形的高度一半的動畫
注意
我們知道,使用 CAAnimation 如果不做額外的操作欲逃,動畫會在結(jié)束之后返回到初始狀態(tài)找蜜。或許你會這么設(shè)置:
radiusAnimation.fillMode = kCAFillModeForwards; radiusAnimation.removedOnCompletion = NO;
但這不是正確的方式稳析。正確的做法可以參考 WWDC 2011 中的 session 421 - Core Animation Essentials洗做。
Session 中推薦的做法是先顯式地改變 Model Layer 的對應(yīng)屬性,再應(yīng)用動畫迈着。這樣一來竭望,我們甚至省去了 toValue。
因?yàn)?cornerRadius 也是 Animatable 的裕菠,所以可以作為 KeyPath 進(jìn)行動畫咬清。首先顯式地設(shè)定屬性的終止?fàn)顟B(tài),為進(jìn)度條高度的 1/2 : ZMButtonSize().height/2. 設(shè)置好起始狀態(tài)奴潘。
static CGSize ZMButtonSize() {
return CGSizeMake(100, 100);
}
-
self.layer.cornerRadius=ZMButtonSize().height/2;
CABasicAnimation *cornerRadiusAnimation=[CABasicAnimation animationWithKeyPath:@"cornerRadius"];
cornerRadiusAnimation.delegate=self;
cornerRadiusAnimation.duration=0.2;
cornerRadiusAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
cornerRadiusAnimation.fromValue=@(self.frame.size.height/2);[self.layer addAnimation:cornerRadiusAnimation forKey:@"cornerRadiusAnimation"];
在Animation的代理方法里動畫一開始讓checkButton的bounds改變
-(void)animationDidStart:(CAAnimation *)anim
{
if([[self.layer animationForKey:@"cornerRadiusAnimation"] isEqual:anim])
{
[UIView animateWithDuration:0.6f delay:0.0f usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.bounds = CGRectMake(0, 0, ZMButtonSize().height, ZMButtonSize().height);
self.backgroundColor=[UIColor colorWithRed:1.00f green:0.80f blue:0.56f alpha:1.00f];
} completion:^(BOOL finished) {
[self.layer removeAllAnimations];
[self checkAnimation];
}];
}
}
動畫第二步畫會動的對號
在checkButton的bounds改變完成是在checkButton上畫一個(gè)對號
這時(shí)候就用到了CAShapeLayer的 strokeStart, strokeEnd旧烧,在動畫時(shí)設(shè)置KeyPath:為"strokeEnd",從0到1,這樣一個(gè)動畫的對號就出來了画髓。
CAShapeLayer *shape=[CAShapeLayer layer];
UIBezierPath *bezierPath=[UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(self.frame.size.width/4, self.frame.size.height/2)];
[bezierPath addLineToPoint:CGPointMake(self.frame.size.width/2, self.frame.size.height/4*3)];
[bezierPath addLineToPoint:CGPointMake(self.frame.size.width/4*3, self.frame.size.height/3)];
//UIBezierPath只是告訴路徑給CAShapeLayer掘剪,具體這個(gè)shpe什么樣子由CAShapeLayer來決定
//所以一些屬于lineWidth,fillColor是在shpe上設(shè)置的奈虾,在UIBezierPath上設(shè)置無效
shape.lineWidth=17;
shape.fillColor=[UIColor clearColor].CGColor;
shape.strokeColor=[UIColor colorWithRed:0.76f green:0.89f blue:0.89f alpha:1.00f].CGColor;
shape.lineCap = kCALineCapRound;
shape.lineJoin = kCALineJoinRound;
shape.path=bezierPath.CGPath;
[self.layer addSublayer:shape];
CABasicAnimation *checkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
checkAnimation.duration = 0.5f;
checkAnimation.fromValue = @(0.0f);
checkAnimation.toValue = @(1.0f);
checkAnimation.delegate = self;
[shape addAnimation:checkAnimation forKey:@"checkAnimation"];
理論上夺谁,所有描線的動畫你都可以用這種方式先指定一個(gè) path 然后改變 strokeEnd, strokeStart 來實(shí)現(xiàn)廉赔。
如果感覺這篇文章對您有所幫助,順手點(diǎn)個(gè)喜歡匾鸥,謝謝啦
代碼放在了GitHub上大家可以下載蜡塌。