轉 貝塞爾曲線與幀動畫

參考來自下面的文章,這篇文章被轉了很多次,原文都不見了

http://www.cnblogs.com/moyunmo/p/3600091.html?utm_source=tuicool&utm_medium=referral

首先說貝塞爾的各種劃線方法

1.利用UIbezier的初始化方法,在UIView上畫bezierPath

a.利用UIbezier的初始化方法,可以創建出圓形,矩形,圓角矩形

b.使用moveToPoint設置起始點,使用addLineToPoint增加點

下面的類繼承于UIView,當此CircleView添加到父視圖上時,會自動調用drawRect方法

[objc]view plaincopy

//弧度轉角度

#define?RADIANS_TO_DEGREES(radians)?((radians)?*?(180.0?/?M_PI))

//角度轉弧度

#define?DEGREES_TO_RADIANS(angle)?((angle)?/?180.0?*?M_PI)

#import?"CircleView.h"

@implementationCircleView

-(void)drawRect:(CGRect)rect

{

//1.圓形

UIBezierPath*bPath?=?[UIBezierPathbezierPathWithArcCenter:CGPointMake(300,300)radius:50

startAngle:?DEGREES_TO_RADIANS(135)endAngle:M_PI*2clockwise:YES];

//設置顏色

[[UIColorredColor]setStroke];

//設置線寬

[bPathsetLineWidth:5];

//繪制

[bPathstroke];

//2.橢圓

UIBezierPath*ovalPath?=?[UIBezierPathbezierPathWithOvalInRect:CGRectMake(200,150,100,200)];

[ovalPathsetLineWidth:5];

[ovalPathstroke];

//3.矩形

UIBezierPath*myBezierPath?=?[UIBezierPathbezierPathWithRect:CGRectMake(20,20,100,50)];

[[UIColorwhiteColor]setStroke];

[myBezierPathsetLineWidth:5];

[myBezierPathstroke];

//4.圓角矩形

//UIRectCorner可以設置?哪幾個角是圓角,其他不變

UIBezierPath*tBPath?=?[UIBezierPathbezierPathWithRoundedRect:CGRectMake(220,20,100,100)

byRoundingCorners:UIRectCornerTopLeft?|?UIRectCornerBottomLeftcornerRadii:CGSizeMake(20,20)];

[[UIColorgreenColor]setStroke];

[tBPathsetLineWidth:5];

[tBPathstroke];

//5.通過添加點生成任意圖形

UIBezierPath*?aPath?=?[UIBezierPathbezierPath];

aPath.lineWidth=15.0;

aPath.lineCapStyle=?kCGLineCapButt;//線條終點

//round?圓形

//butt?平的?默認值?把線連接到精準的終點

//Square?平的,會把線延伸到終點再加上線寬的一半

aPath.lineJoinStyle=?kCGLineJoinBevel;//拐點處理

//bevel?斜角斜面,角的外側是平的不圓滑

//miter?斜接?角的外側是尖的

//round?圓角

//這是起點

[aPathmoveToPoint:CGPointMake(100.0,200.0)];

//添加點

[aPathaddLineToPoint:CGPointMake(200.0,240.0)];

[aPathaddLineToPoint:CGPointMake(160,340)];

[aPathaddLineToPoint:CGPointMake(40.0,340)];

[aPathaddLineToPoint:CGPointMake(10.0,240.0)];

[aPathclosePath];//第五條線通過調用closePath方法得到的

[aPathstroke];//Draws?line?根據坐標點連線

}

@end

2.二次曲線和三次曲線

盜圖兩張,他們解釋了控制點是怎么回事

劃線方法很簡單

二次曲線

[objc]view plaincopy

//創建一條貝塞爾

UIBezierPath*?aPath?=?[UIBezierPathbezierPath];

aPath.lineWidth=5.0;//寬度

aPath.lineCapStyle=?kCGLineCapRound;//線條拐角

aPath.lineJoinStyle=?kCGLineJoinRound;//終點處理

//起始點

[aPathmoveToPoint:CGPointMake(20,100)];

//添加兩個控制點

[aPathaddQuadCurveToPoint:CGPointMake(220,100)controlPoint:CGPointMake(170,0)];

//劃線

[aPathstroke];

三次曲線

[objc]view plaincopy

//三次曲線

UIBezierPath*?bPath?=?[UIBezierPathbezierPath];

bPath.lineWidth=5.0;

bPath.lineCapStyle=?kCGLineCapRound;//線條拐角

bPath.lineJoinStyle=?kCGLineCapRound;//終點處理

//起始點

[bPathmoveToPoint:CGPointMake(20,250)];

//添加兩個控制點

[bPathaddCurveToPoint:CGPointMake(350,250)controlPoint1:CGPointMake(310,200)controlPoint2:CGPointMake(210,400)];

[bPathstroke];

3.了解一下底層的Core Graphics

這篇文章說的夠了

http://www.mamicode.com/info-detail-841887.html

[objc]view plaincopy

-(void)drawRect:(CGRect)rect

{

//?Create?the?path?data

//創建路徑時間

CGMutablePathRef?cgPath?=?CGPathCreateMutable();

//cgPath的畫圖接口

//給一個cgPath里面添加了多個樣式,圓和橢圓會發生關聯

//兩個橢圓互不影響

CGPathAddEllipseInRect(cgPath,NULL,?CGRectMake(100,100,50,100));

CGPathAddEllipseInRect(cgPath,NULL,?CGRectMake(250,250,100,50));

//矩形

CGPathAddRect(cgPath,NULL,?CGRectMake(200,500,30,100));

//????圓形

//????CGPathAddArc(cgPath,?NULL,?120,?400,?100,?0,?M_PI*2,?YES);

//下面兩句要搭配,先有起點

CGPathMoveToPoint(cgPath,NULL,200,300);

//加一段弧

CGPathAddArcToPoint(cgPath,NULL,320,250,?DEGREES_TO_RADIANS(150),?M_PI*2,50);

//把CGPath賦給貝塞爾曲線

UIBezierPath*?aPath?=?[UIBezierPathbezierPath];

aPath.CGPath=?cgPath;

aPath.usesEvenOddFillRule=YES;

//并不在ARC的管理范圍之內。所以需要手動釋放對象,釋放cgPath

CGPathRelease(cgPath);

//劃線

[[UIColorredColor]setStroke];

[aPathsetLineWidth:5];

[aPathstroke];

}

4.通過shapeLayer畫線

這樣就不用去UIView的drawRect方法里面畫圖了,也就是可以在ViewController里面繪制了

[objc]view plaincopy

//ShapeLayer

-(void)layerAnimation

{

//貝塞爾畫圓

UIBezierPath*path?=?[UIBezierPathbezierPathWithArcCenter:CGPointMake(100,100)radius:100startAngle:0endAngle:M_PIclockwise:NO];

//初始化shapeLayer

self.myShapeLayer=?[CAShapeLayerlayer];

_myShapeLayer.frame=?_redView.bounds;

_myShapeLayer.strokeColor=?[UIColorgreenColor].CGColor;//邊沿線色

_myShapeLayer.fillColor=?[UIColorgrayColor].CGColor;//填充色

_myShapeLayer.lineJoin=?kCALineJoinMiter;//線拐點的類型

_myShapeLayer.lineCap=?kCALineCapSquare;//線終點

//從貝塞爾曲線獲得形狀

_myShapeLayer.path=?path.CGPath;

//線條寬度

_myShapeLayer.lineWidth=10;

//起始和終止

_myShapeLayer.strokeStart=0.0;

_myShapeLayer.strokeEnd=1.0;

//將layer添加進圖層

[self.redView.layeraddSublayer:_myShapeLayer];

}

二、關鍵幀動畫

[objc]view plaincopy

//關鍵幀動畫

-(void)layerKeyFrameAnimation

{

//畫一個path

UIBezierPath*path?=?[UIBezierPathbezierPath];

[pathmoveToPoint:CGPointMake(-40,100)];

[pathaddLineToPoint:CGPointMake(360,100)];

[pathaddLineToPoint:CGPointMake(360,200)];

[pathaddLineToPoint:CGPointMake(-40,200)];

[pathaddLineToPoint:CGPointMake(-40,300)];

[pathaddLineToPoint:CGPointMake(360,300)];

//幾個固定點

NSValue*orginalValue?=?[NSValuevalueWithCGPoint:self.redView.layer.position];

NSValue*value_1=?[NSValuevalueWithCGPoint:CGPointMake(300,300)];

NSValue*value_2=?[NSValuevalueWithCGPoint:CGPointMake(400,300)];

NSValue*value_3=?[NSValuevalueWithCGPoint:CGPointMake(400,400)];

//變動的屬性,keyPath后面跟的屬性是CALayer的屬性

CAKeyframeAnimation*keyFA?=?[CAKeyframeAnimationanimationWithKeyPath:@"position"];

//value數組,放所有位置信息,如果設置path,此項會被忽略

keyFA.values=?@[orginalValue,value_1,value_2,value_3];

//動畫路徑

//????keyFA.path?=?path.CGPath;

//該屬性是一個數組,用以指定每個子路徑(AB,BC,CD)的時間。如果你沒有顯式地對keyTimes進行設置,則系統會默認每條子路徑的時間為:ti=duration/(幀數),即每條子路徑的duration相等

keyFA.keyTimes=?@[@(0.0),@(0.5),@(0.9),@(2)];

//動畫總時間

keyFA.duration=5.0f;

//重復次數,小于0無限重復

keyFA.repeatCount=10;

/*

這個屬性用以指定時間函數,類似于運動的加速度

kCAMediaTimingFunctionLinear//線性

kCAMediaTimingFunctionEaseIn//淡入

kCAMediaTimingFunctionEaseOut//淡出

kCAMediaTimingFunctionEaseInEaseOut//淡入淡出

kCAMediaTimingFunctionDefault//默認

*/

keyFA.timingFunction=?[CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionLinear];

/*

fillMode的作用就是決定當前對象過了非active時間段的行為.?比如動畫開始之前,動畫結束之后。如果是一個動畫CAAnimation,則需要將其removedOnCompletion設置為NO,要不然fillMode不起作用.

下面來講各個fillMode的意義

kCAFillModeRemoved?這個是默認值,也就是說當動畫開始前和動畫結束后,動畫對layer都沒有影響,動畫結束后,layer會恢復到之前的狀態

kCAFillModeForwards?當動畫結束后,layer會一直保持著動畫最后的狀態

kCAFillModeBackwards?這個和kCAFillModeForwards是相對的,就是在動畫開始前,你只要將動畫加入了一個layer,layer便立即進入動畫的初始狀態并等待動畫開始.你可以這樣設定測試代碼,將一個動畫加入一個layer的時候延遲5秒執行.然后就會發現在動畫沒有開始的時候,只要動畫被加入了layer,layer便處于動畫初始狀態

kCAFillModeBoth?理解了上面兩個,這個就很好理解了,這個其實就是上面兩個的合成.動畫加入后開始之前,layer便處于動畫初始狀態,動畫結束后layer保持動畫最后的狀態.

//添加動畫

*/

keyFA.fillMode=?kCAFillModeForwards;

/*

在關鍵幀動畫中還有一個非常重要的參數,那便是calculationMode,計算模式.該屬性決定了物體在每個子路徑下是跳著走還是勻速走,跟timeFunctions屬性有點類似

其主要針對的是每一幀的內容為一個座標點的情況,也就是對anchorPoint?和?position?進行的動畫.當在平面座標系中有多個離散的點的時候,可以是離散的,也可以直線相連后進行插值計算,也可以使用圓滑的曲線將他們相連后進行插值計算.?calculationMode目前提供如下幾種模式

kCAAnimationLinear?calculationMode的默認值,表示當關鍵幀為座標點的時候,關鍵幀之間直接直線相連進行插值計算;

kCAAnimationDiscrete?離散的,就是不進行插值計算,所有關鍵幀直接逐個進行顯示;

kCAAnimationPaced?使得動畫均勻進行,而不是按keyTimes設置的或者按關鍵幀平分時間,此時keyTimes和timingFunctions無效;

kCAAnimationCubic?對關鍵幀為座標點的關鍵幀進行圓滑曲線相連后插值計算,對于曲線的形狀還可以通過tensionValues,continuityValues,biasValues來進行調整自定義,這里的數學原理是Kochanek–Bartels?spline,這里的主要目的是使得運行的軌跡變得圓滑;

kCAAnimationCubicPaced?看這個名字就知道和kCAAnimationCubic有一定聯系,其實就是在kCAAnimationCubic的基礎上使得動畫運行變得均勻,就是系統時間內運動的距離相同,此時keyTimes以及timingFunctions也是無效的.

*/

keyFA.calculationMode=?kCAAnimationPaced;

//旋轉的模式,auto就是沿著切線方向動,autoReverse就是轉180度沿著切線動

keyFA.rotationMode=?kCAAnimationRotateAuto;

//結束后是否移除動畫

keyFrameAnimation.removedOnCompletion=NO;

//添加動畫

[self.redView.layeraddAnimation:keyFAforKey:@""];

}

這里有個泡泡動畫的demo,結合了貝塞爾曲線和幀動畫,很精致

https://github.com/bnb173yjx/BubbleAnimationDemo

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容