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

一、CAShapeLayer

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

二、UIBezierPath 和 貝塞爾曲線

2.1什么是貝塞爾曲線?

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

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

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



接著,我們?cè)贏B和BC線段上找出點(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在第一條線段上從起點(diǎn)A,移動(dòng)到終點(diǎn)B,找出所有點(diǎn)F,并將它們連起來(lái)。最后你會(huì)發(fā)現(xiàn),你得到了一條非常光滑的曲線,這條就是傳說(shuō)中的,貝塞爾曲線。


二階貝塞爾曲線

下面是三階四階和五階。


三階貝塞爾曲線
四階貝塞爾曲線
五階貝塞爾曲線

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


一階貝塞爾曲線

2.3怎么使用貝塞爾曲線?

首先,要明確的一點(diǎn)是,對(duì)于貝塞爾曲線來(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ù),貝塞爾曲線被分為一階貝塞爾曲線(0個(gè)控制點(diǎn))、二階貝塞爾曲線(1個(gè)控制點(diǎn))、三階貝塞爾曲線(2個(gè)控制點(diǎn))等等。

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

用法一:UIBezierPath+CAShapeLayer畫(huà)線,畫(huà)圖

CAShapeLayer的path屬性可以由UIBezierPath來(lái)提供,從而可以畫(huà)線畫(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è)置虛線
    animLayer.lineDashPattern = @[@20,@20];
    //線拐點(diǎn)處的樣式:
    animLayer.lineJoin = kCALineJoinRound;
    //線終點(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"];

折線

    // 線的路徑
    _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]; //第五條線通過(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];

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

    // 畫(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]; // 添加一條弧線
    [_path closePath];

//一階曲線

     _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)];

//二階曲線

     _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à)。

用法三:用貝塞爾曲線做變形

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

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

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

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

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

http://easings.net

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

  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è)置速率曲線
  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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容