探究CAShapeLayer & UIBezierPath畫(huà)線(xiàn)、畫(huà)圖地淀、動(dòng)畫(huà)

一失球、CAShapeLayer

  • CAShapeLayer 繼承與CALayer( 主要用于設(shè)置圖層的形狀)
屬性名 描述
path CGPathRef 對(duì)象,圖形邊線(xiàn)路徑
lineWidth 邊線(xiàn)的寬度
strokeColor 邊線(xiàn)的顏色
lineDashPattern 設(shè)置邊線(xiàn)的樣式帮毁,默認(rèn)為實(shí)線(xiàn)实苞,該數(shù)組為一個(gè)NSNumber數(shù)組,數(shù)組中的數(shù)值依次表示虛線(xiàn)中烈疚,單個(gè)線(xiàn)的長(zhǎng)度黔牵,和空白的長(zhǎng)度,如:數(shù)組@[2,2,3,4] 表示 有長(zhǎng)度為2的線(xiàn)爷肝,長(zhǎng)度為2的空白猾浦,長(zhǎng)度為3的線(xiàn),長(zhǎng)度為4的空白 不斷循環(huán)后組成的虛線(xiàn)灯抛。
lineCap 線(xiàn)終點(diǎn)的樣式:
默認(rèn) kCALineCapButt
kCALineCapRound
kCALineCapSquare
lineJoin 線(xiàn)拐點(diǎn)處的樣式:
默認(rèn) kCALineJoinMiter
kCALineJoinRound
kCALineJoinBeve
strokeStart strokeEnd CGFloat類(lèi)型金赦,[0,1] 表示畫(huà)邊線(xiàn)的起點(diǎn)和終點(diǎn)(即在路徑上的百分比)
fillColor CGColorRef對(duì)象,圖形填充色牧愁,默認(rèn)為黑色

二素邪、UIBezierPath 和 貝塞爾曲線(xiàn)

2.1什么是貝塞爾曲線(xiàn)?

法國(guó)數(shù)學(xué)家 Paul de Casteljau 在1959年提供的一種 算法猪半。根據(jù)這個(gè)算法兔朦,就可以只通過(guò)很少的控制點(diǎn),去生成復(fù)雜的平滑曲線(xiàn)磨确,也就是貝塞爾曲線(xiàn)沽甥。

2.2貝塞爾曲線(xiàn)是怎么畫(huà)出來(lái)的?

首先乏奥,我們?cè)谄矫鎯?nèi)選3個(gè)不同線(xiàn)的點(diǎn)并且依次用線(xiàn)段連接摆舟。如下所示..



接著,我們?cè)贏B和BC線(xiàn)段上找出點(diǎn)D和點(diǎn)E邓了,使得AD/AB = BE/BC恨诱。



再接著,連接DE骗炉,并在DE上找出一點(diǎn)F照宝,使得DF/DE = AD/AB = BE/BC。

然后句葵,根據(jù)我們高中所學(xué)的極限的知識(shí)厕鹃,讓選取的點(diǎn)D在第一條線(xiàn)段上從起點(diǎn)A兢仰,移動(dòng)到終點(diǎn)B,找出所有點(diǎn)F剂碴,并將它們連起來(lái)把将。最后你會(huì)發(fā)現(xiàn),你得到了一條非常光滑的曲線(xiàn)忆矛,這條就是傳說(shuō)中的察蹲,貝塞爾曲線(xiàn)。


二階貝塞爾曲線(xiàn)

下面是三階四階和五階洪碳。


三階貝塞爾曲線(xiàn)
四階貝塞爾曲線(xiàn)
五階貝塞爾曲線(xiàn)

最后提下一递览,這個(gè)是一階


一階貝塞爾曲線(xiàn)

2.3怎么使用貝塞爾曲線(xiàn)?

首先瞳腌,要明確的一點(diǎn)是绞铃,對(duì)于貝塞爾曲線(xiàn)來(lái)說(shuō),最重要的點(diǎn)是嫂侍,數(shù)據(jù)點(diǎn)和控制點(diǎn)儿捧。

  • 數(shù)據(jù)點(diǎn): 指一條路徑的起始點(diǎn)和終止點(diǎn)。
  • 控制點(diǎn):控制點(diǎn)決定了一條路徑的彎曲軌跡挑宠,根據(jù)控制點(diǎn)的個(gè)數(shù)菲盾,貝塞爾曲線(xiàn)被分為一階貝塞爾曲線(xiàn)(0個(gè)控制點(diǎn))、二階貝塞爾曲線(xiàn)(1個(gè)控制點(diǎn))各淀、三階貝塞爾曲線(xiàn)(2個(gè)控制點(diǎn))等等懒鉴。

系統(tǒng)給我們提供了一個(gè)叫做UIBezierPath類(lèi),用它可以畫(huà)簡(jiǎn)單的圓形碎浇,橢圓临谱,矩形,圓角矩形奴璃,也可以通過(guò)添加點(diǎn)去生成任意的圖形悉默,還可以簡(jiǎn)單的創(chuàng)建一條二階貝塞爾曲線(xiàn)和三階貝塞爾曲線(xiàn)。

用法一:UIBezierPath+CAShapeLayer畫(huà)線(xiàn)苟穆,畫(huà)圖

CAShapeLayer的path屬性可以由UIBezierPath來(lái)提供抄课,從而可以畫(huà)線(xiàn)畫(huà)圖。

    CAShapeLayer *animLayer = [CAShapeLayer layer];
    //UIBezierPath提供路徑!!!!!!
    animLayer.path = _path.CGPath;
    //路徑寬度
    animLayer.lineWidth = 5.f;
    //路徑顏色
    animLayer.strokeColor = [UIColor redColor].CGColor;
    //圖形填充顏色
    animLayer.fillColor = [UIColor orangeColor].CGColor;
    //起點(diǎn)
    animLayer.strokeStart = 0;
    //終點(diǎn)
    animLayer.strokeEnd = 1.;
    //設(shè)置虛線(xiàn)
    animLayer.lineDashPattern = @[@20,@20];
    //線(xiàn)拐點(diǎn)處的樣式:
    animLayer.lineJoin = kCALineJoinRound;
    //線(xiàn)終點(diǎn)的樣式
    animLayer.lineCap = kCALineCapRound;
    [self.view.layer addSublayer:animLayer];
    
    //添加路徑動(dòng)畫(huà)
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.fromValue = @(0);
    animation.toValue = @(1.f);
    animation.duration = 2.0f;
    animation.removedOnCompletion = NO;
    animation.fillMode  = kCAFillModeForwards;
    [animLayer addAnimation:animation forKey:@"strokeEnd"];

折線(xiàn)

    // 線(xiàn)的路徑
    _path  = [UIBezierPath bezierPath];
    // 起點(diǎn)
    [_path  moveToPoint:CGPointMake(20, 20)];
    // 其他點(diǎn)
    [_path  addLineToPoint:CGPointMake(160, 160)];
    [_path  addLineToPoint:CGPointMake(180, 50)];

多邊形

    _path = [UIBezierPath bezierPath];
    //這是起點(diǎn)
    [_path moveToPoint:CGPointMake(100.0, 200.0)];
    //添加點(diǎn)
    [_path addLineToPoint:CGPointMake(200.0, 240.0)];
    [_path addLineToPoint:CGPointMake(160, 340)];
    [_path addLineToPoint:CGPointMake(40.0, 340)];
    [_path addLineToPoint:CGPointMake(10.0, 240.0)];
    [_path closePath]; //第五條線(xiàn)通過(guò)調(diào)用closePath方法得到的

矩形

_path = [UIBezierPath bezierPathWithRect:CGRectMake(100, 100, 100, 100)];

圓角矩形

_path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 200, 100) cornerRadius:25];

自定義圓角矩形

 _path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 200, 100) byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(25, 25)];

圓或橢圓

 _path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 100)];

圓弧

//    center       圓心
//    radius       半徑
//    startAngle   開(kāi)始角度
//    endAngle     結(jié)束角度
//    clockwise    順時(shí)針or逆時(shí)針
 _path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(200, 200) radius:100 startAngle:0 endAngle:M_PI clockwise:YES];

折線(xiàn)和弧線(xiàn)構(gòu)成的曲線(xiàn)

    // 畫(huà)弧的中心點(diǎn)
    CGPoint viewCenter = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0); 
    _path = [UIBezierPath bezierPath];
    [_path moveToPoint:viewCenter];
    [_path addArcWithCenter:viewCenter radius:50 startAngle:0 endAngle:M_PI/4*3 clockwise:YES]; // 添加一條弧線(xiàn)
    [_path closePath];

//一階曲線(xiàn)

     _path = [UIBezierPath bezierPath];
     _path.lineWidth = 5.0;//寬度
    //起始點(diǎn)
    [_path moveToPoint:CGPointMake(20, 200)];
    //添加終點(diǎn)和控制點(diǎn)
    [twoPath addQuadCurveToPoint:CGPointMake(220, 200) controlPoint:CGPointMake(120, 0)];

//二階曲線(xiàn)

     _path = [UIBezierPath bezierPath];
     _path.lineWidth = 5.0;
    //起始點(diǎn)
    [ _path moveToPoint:CGPointMake(0, 200)];
    //添加兩個(gè)控制點(diǎn)
    [ _path addCurveToPoint:CGPointMake(360, 200) controlPoint1:CGPointMake(135, 0) controlPoint2:CGPointMake(225, 400)];

用法二:UIBezierPath+CAKeyframeAnimation 為關(guān)鍵幀動(dòng)畫(huà)提供動(dòng)畫(huà)路徑

可以參考iOS動(dòng)畫(huà)梳理與總結(jié) (一) 核心動(dòng)畫(huà)雳旅。

用法三:用貝塞爾曲線(xiàn)做變形

可參考本節(jié)提供的demo跟磨。

用法四:用貝塞爾曲線(xiàn)做緩沖動(dòng)畫(huà)

做動(dòng)畫(huà)最主要的一點(diǎn),就是要讓動(dòng)畫(huà)達(dá)到很自然的效果攒盈。所以就需要我們給動(dòng)畫(huà)設(shè)置一條順滑的速率曲線(xiàn)抵拘。
這個(gè)時(shí)候就不得不提到 CAMediaTimingFunction
CAMediaTimingFunction 的主要用法可以理解為我們?cè)谝粋€(gè)二維坐標(biāo)系上建議一條或曲線(xiàn)或直線(xiàn)的函數(shù)沦童,這個(gè)函數(shù)的斜率就是動(dòng)畫(huà)的速度仑濒,斜率的改變量也就是導(dǎo)數(shù)則為加速度。理論上來(lái)說(shuō)偷遗,這個(gè)坐標(biāo)系上的任何曲線(xiàn)都可以用來(lái)當(dāng)做加速動(dòng)畫(huà)墩瞳。然而CAMediaTimingFunction 只給我們提供了一個(gè)三次貝塞爾曲線(xiàn)的函數(shù),它可以生成三次貝塞爾曲線(xiàn)所能生成的所有緩沖函數(shù)氏豌。

這里剛好可以介紹 一個(gè) 兩個(gè)好用的網(wǎng)站: http://www.roblaplaca.com/examples/bezierBuilder

這個(gè)網(wǎng)站可以做到可視化的修改兩個(gè)控制點(diǎn)喉酌,來(lái)達(dá)到生成一條三階貝塞爾曲線(xiàn),并且還會(huì)給出兩個(gè)控制點(diǎn)的具體坐標(biāo)泵喘,以及右邊還可以看到這條曲線(xiàn)產(chǎn)生的動(dòng)畫(huà)會(huì)做怎樣的速度改變泪电。也就是說(shuō),只要我們能拿到兩個(gè)控制點(diǎn)的坐標(biāo)纪铺,就可以用來(lái)控制動(dòng)畫(huà)了相速。

http://easings.net

這個(gè)網(wǎng)站提供了豐富的曲線(xiàn)類(lèi)型可供選擇,圖表旁還有一個(gè)小動(dòng)畫(huà)預(yù)覽鲜锚,非常直觀(guān)突诬。

  UIView *demoView = [[UIView alloc] initWithFrame:CGRectMake(0, 300,100 ,100 )];
  demoView.backgroundColor = [UIColor redColor];
  [self.view addSubview:demoView];
  CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
  animation.fromValue = @(CGPointMake(50, 300));
  animation.toValue = @(CGPointMake(WIDTH-50, 300));
  animation.duration = 5.0f;
  animation.autoreverses = YES;
  animation.fillMode = kCAFillModeForwards;
  animation.removedOnCompletion = NO;
    //設(shè)置速率曲線(xiàn)
  animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.48 :0.01 :0.48 :1.01];
  [demoView.layer addAnimation:animation forKey:@"position"];

本章demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芜繁,隨后出現(xiàn)的幾起案子旺隙,更是在濱河造成了極大的恐慌,老刑警劉巖骏令,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔬捷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡榔袋,警方通過(guò)查閱死者的電腦和手機(jī)周拐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摘昌,“玉大人速妖,你說(shuō)我怎么就攤上這事〈侠瑁” “怎么了罕容?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)稿饰。 經(jīng)常有香客問(wèn)我锦秒,道長(zhǎng),這世上最難降的妖魔是什么喉镰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任旅择,我火速辦了婚禮,結(jié)果婚禮上侣姆,老公的妹妹穿的比我還像新娘生真。我一直安慰自己沉噩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布柱蟀。 她就那樣靜靜地躺著川蒙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪长已。 梳的紋絲不亂的頭發(fā)上畜眨,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音术瓮,去河邊找鬼康聂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛胞四,可吹牛的內(nèi)容都是我干的恬汁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辜伟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蕊连!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起游昼,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤甘苍,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后烘豌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體载庭,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年廊佩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了囚聚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡标锄,死狀恐怖顽铸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情料皇,我是刑警寧澤谓松,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站践剂,受9級(jí)特大地震影響鬼譬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逊脯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一优质、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦巩螃、人聲如沸演怎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颤枪。三九已至,卻和暖如春淑际,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扇住。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工春缕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艘蹋。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓锄贼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親女阀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宅荤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345