一、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à)了。

這個(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"];





