iOS動(dòng)畫之CAShapeLayer(一)提交動(dòng)畫

checkButton1.gif

今天動(dòng)畫的主要用CAShapeLayer和貝塞爾曲線做一個(gè)提交的動(dòng)畫,也是沒有什么難度的

先簡單的介紹下CAShapeLayer

  1. CAShapeLayer繼承自CALayer,可使用CALayer的所有屬性
  2. CAShapeLayer需要和貝塞爾曲線配合使用才有意義。
    Shape:形狀,貝塞爾曲線可以為其提供形狀,而單獨(dú)使用CAShapeLayer是沒有任何意義的。
  3. 使用CAShapeLayer與貝塞爾曲線可以實(shí)現(xiàn)不在view的DrawRect方法中畫出一些想要的圖形

關(guān)于CAShapeLayer和DrawRect的比較

DrawRect:DrawRect屬于CoreGraphic框架,占用CPU,消耗性能大
CAShapeLayer:CAShapeLayer屬于CoreAnimation框架,通過GPU來渲染圖形,節(jié)省性能。動(dòng)畫渲染直接提交給手機(jī)GPU,不消耗內(nèi)存

貝塞爾曲線與CAShapeLayer的關(guān)系

  1. CAShapeLayer中shape代表形狀的意思,所以需要形狀才能生效
  2. 貝塞爾曲線可以創(chuàng)建基于矢量的路徑
  3. 貝塞爾曲線給CAShapeLayer提供路徑,CAShapeLayer在提供的路徑中進(jìn)行渲染。路徑會(huì)閉環(huán),所以繪制出了Shape
  4. 用于CAShapeLayer的貝塞爾曲線作為Path,其path是一個(gè)首尾相接的閉環(huán)的曲線,即使該貝塞爾曲線不是一個(gè)閉環(huán)的曲線

以上文字來源于網(wǎng)絡(luò),哈哈

如果有同學(xué)對(duì)UIBezierPath不熟悉的請(qǐng)看這里

CAShapeLayer的介紹

上面的介紹也說了貝塞爾曲線給CAShapeLayer提供路徑,CAShapeLayer在提供的路徑中進(jìn)行渲染,把路徑用以形狀的形式展示出來,CAShapeLayer最重要的屬性就是下面三個(gè):

 //動(dòng)畫的路徑
@property(nullable) CGPathRef path;

//描述path路徑從哪里開始
@property CGFloat strokeStart;
//描述path路徑從哪里結(jié)束
@property CGFloat strokeEnd;
 這兩個(gè)值的范圍是[0,1],

接下來我們先畫一個(gè)不會(huì)動(dòng)的 對(duì)號(hào) 來學(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 一半的矩形”
checkButton

CAShapeLayer的基本用法就是這樣接下來就是動(dòng)畫了

動(dòng)畫第一步長方形變圓形

先添加一個(gè)checkButton的cornerRadius變?yōu)閳A形的高度一半的動(dòng)畫

注意
我們知道,使用 CAAnimation 如果不做額外的操作,動(dòng)畫會(huì)在結(jié)束之后返回到初始狀態(tài)。或許你會(huì)這么設(shè)置:

radiusAnimation.fillMode = kCAFillModeForwards; radiusAnimation.removedOnCompletion = NO;

但這不是正確的方式。正確的做法可以參考 WWDC 2011 中的 session 421 - Core Animation Essentials。
Session 中推薦的做法是先顯式地改變 Model Layer 的對(duì)應(yīng)屬性,再應(yīng)用動(dòng)畫。這樣一來,我們甚至省去了 toValue。
因?yàn)?cornerRadius 也是 Animatable 的,所以可以作為 KeyPath 進(jìn)行動(dòng)畫。首先顯式地設(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的代理方法里動(dòng)畫一開始讓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];
        
    }];

 }

}

動(dòng)畫第二步畫會(huì)動(dòng)的對(duì)號(hào)

在checkButton的bounds改變完成是在checkButton上畫一個(gè)對(duì)號(hào)

這時(shí)候就用到了CAShapeLayer的 strokeStart, strokeEnd,在動(dòng)畫時(shí)設(shè)置KeyPath:為"strokeEnd",從0到1,這樣一個(gè)動(dòng)畫的對(duì)號(hào)就出來了。

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"];

理論上,所有描線的動(dòng)畫你都可以用這種方式先指定一個(gè) path 然后改變 strokeEnd, strokeStart 來實(shí)現(xiàn)。

如果感覺這篇文章對(duì)您有所幫助,順手點(diǎn)個(gè)喜歡,謝謝啦
代碼放在了GitHub上大家可以下載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評(píng)論 3 422
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,960評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,914評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,089評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,340評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評(píng)論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,834評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,106評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容