一、貝塞爾曲線
參考來自下面的文章,這篇文章被轉(zhuǎn)了很多次,原文都不見了
http://www.cnblogs.com/moyunmo/p/3600091.html?utm_source=tuicool&utm_medium=referral
1.利用UIbezier的初始化方法,在UIView上畫bezierPath
a.利用UIbezier的初始化方法,可以創(chuàng)建出圓形,矩形,圓角矩形
b.使用moveToPoint設(shè)置起始點(diǎn),使用addLineToPoint增加點(diǎn)
下面的類繼承于UIView,當(dāng)此CircleView添加到父視圖上時(shí),會(huì)自動(dòng)調(diào)用drawRect方法
//弧度轉(zhuǎn)角度
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
//角度轉(zhuǎn)弧度
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
#import "CircleView.h"
@implementation CircleView
-(void)drawRect:(CGRect)rect
{
//1.圓形
UIBezierPath *bPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(300, 300) radius:50
startAngle: DEGREES_TO_RADIANS(135) endAngle:M_PI*2 clockwise:YES];
//設(shè)置顏色
[[UIColor redColor]setStroke];
//設(shè)置線寬
[bPath setLineWidth:5];
//繪制
[bPath stroke];
//2.橢圓
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(200, 150, 100, 200)];
[ovalPath setLineWidth:5];
[ovalPath stroke];
//3.矩形
UIBezierPath *myBezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, 100, 50)];
[[UIColor whiteColor]setStroke];
[myBezierPath setLineWidth:5];
[myBezierPath stroke];
//4.圓角矩形
//UIRectCorner可以設(shè)置 哪幾個(gè)角是圓角,其他不變
UIBezierPath *tBPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(220, 20, 100, 100)
byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake(20, 20)];
[[UIColor greenColor]setStroke];
[tBPath setLineWidth:5];
[tBPath stroke];
//5.通過添加點(diǎn)生成任意圖形
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 15.0;
aPath.lineCapStyle = kCGLineCapButt; //線條終點(diǎn)
//round 圓形
//butt 平的 默認(rèn)值 把線連接到精準(zhǔn)的終點(diǎn)
//Square 平的,會(huì)把線延伸到終點(diǎn)再加上線寬的一半
aPath.lineJoinStyle = kCGLineJoinBevel; //拐點(diǎn)處理
//bevel 斜角斜面,角的外側(cè)是平的不圓滑
//miter 斜接 角的外側(cè)是尖的
//round 圓角
//這是起點(diǎn)
[aPath moveToPoint:CGPointMake(100.0, 200.0)];
//添加點(diǎn)
[aPath addLineToPoint:CGPointMake(200.0, 240.0)];
[aPath addLineToPoint:CGPointMake(160, 340)];
[aPath addLineToPoint:CGPointMake(40.0, 340)];
[aPath addLineToPoint:CGPointMake(10.0, 240.0)];
[aPath closePath]; //第五條線通過調(diào)用closePath方法得到的
[aPath stroke]; //Draws line 根據(jù)坐標(biāo)點(diǎn)連線
}
@end
2.二次曲線和三次曲線
盜圖兩張,他們解釋了控制點(diǎn)
劃線方法很簡單
二次曲線
//創(chuàng)建一條貝塞爾
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5.0;//寬度
aPath.lineCapStyle = kCGLineCapRound; //線條拐角
aPath.lineJoinStyle = kCGLineJoinRound; //終點(diǎn)處理
//起始點(diǎn)
[aPath moveToPoint:CGPointMake(20, 100)];
//添加兩個(gè)控制點(diǎn)
[aPath addQuadCurveToPoint:CGPointMake(220, 100) controlPoint:CGPointMake(170, 0)];
//劃線
[aPath stroke];
三次曲線
//三次曲線
UIBezierPath* bPath = [UIBezierPath bezierPath];
bPath.lineWidth = 5.0;
bPath.lineCapStyle = kCGLineCapRound; //線條拐角
bPath.lineJoinStyle = kCGLineCapRound; //終點(diǎn)處理
//起始點(diǎn)
[bPath moveToPoint:CGPointMake(20, 250)];
//添加兩個(gè)控制點(diǎn)
[bPath addCurveToPoint:CGPointMake(350, 250) controlPoint1:CGPointMake(310, 200) controlPoint2:CGPointMake(210, 400)];
[bPath stroke];
3.了解一下底層的Core Graphics
這篇文章
http://www.mamicode.com/info-detail-841887.html
-(void)drawRect:(CGRect)rect
{
// Create the path data
//創(chuàng)建路徑時(shí)間
CGMutablePathRef cgPath = CGPathCreateMutable();
//cgPath的畫圖接口
//給一個(gè)cgPath里面添加了多個(gè)樣式,圓和橢圓會(huì)發(fā)生關(guān)聯(lián)
//兩個(gè)橢圓互不影響
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);
//下面兩句要搭配,先有起點(diǎn)
CGPathMoveToPoint(cgPath, NULL, 200, 300);
//加一段弧
CGPathAddArcToPoint(cgPath, NULL, 320, 250, DEGREES_TO_RADIANS(150), M_PI*2, 50);
//把CGPath賦給貝塞爾曲線
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.CGPath = cgPath;
aPath.usesEvenOddFillRule = YES;
//并不在ARC的管理范圍之內(nèi)。所以需要手動(dòng)釋放對(duì)象,釋放cgPath
CGPathRelease(cgPath);
//劃線
[[UIColor redColor]setStroke];
[aPath setLineWidth:5];
[aPath stroke];
}
4.通過shapeLayer畫線
這樣就不用去UIView的drawRect方法里面畫圖了
//ShapeLayer
-(void)layerAnimation
{
//貝塞爾畫圓
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:100 startAngle:0 endAngle:M_PI clockwise:NO];
//初始化shapeLayer
self.myShapeLayer = [CAShapeLayer layer];
_myShapeLayer.frame = _redView.bounds;
_myShapeLayer.strokeColor = [UIColor greenColor].CGColor;//邊沿線色
_myShapeLayer.fillColor = [UIColor grayColor].CGColor;//填充色
_myShapeLayer.lineJoin = kCALineJoinMiter;//線拐點(diǎn)的類型
_myShapeLayer.lineCap = kCALineCapSquare;//線終點(diǎn)
//從貝塞爾曲線獲得形狀
_myShapeLayer.path = path.CGPath;
//線條寬度
_myShapeLayer.lineWidth = 10;
//起始和終止
_myShapeLayer.strokeStart = 0.0;
_myShapeLayer.strokeEnd = 1.0;
//將layer添加進(jìn)圖層
[self.redView.layer addSublayer:_myShapeLayer];
}
二、關(guān)鍵幀動(dòng)畫
//關(guān)鍵幀動(dòng)畫
-(void)layerKeyFrameAnimation
{
//畫一個(gè)path
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(-40, 100)];
[path addLineToPoint:CGPointMake(360, 100)];
[path addLineToPoint:CGPointMake(360, 200)];
[path addLineToPoint:CGPointMake(-40, 200)];
[path addLineToPoint:CGPointMake(-40, 300)];
[path addLineToPoint:CGPointMake(360, 300)];
//幾個(gè)固定點(diǎn)
NSValue *orginalValue = [NSValue valueWithCGPoint:self.redView.layer.position];
NSValue *value_1 = [NSValue valueWithCGPoint:CGPointMake(300, 300)];
NSValue *value_2 = [NSValue valueWithCGPoint:CGPointMake(400, 300)];
NSValue *value_3 = [NSValue valueWithCGPoint:CGPointMake(400, 400)];
//變動(dòng)的屬性,keyPath后面跟的屬性是CALayer的屬性
CAKeyframeAnimation *keyFA = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//value數(shù)組,放所有位置信息,如果設(shè)置path,此項(xiàng)會(huì)被忽略
keyFA.values = @[orginalValue,value_1,value_2,value_3];
//動(dòng)畫路徑
// keyFA.path = path.CGPath;
//該屬性是一個(gè)數(shù)組,用以指定每個(gè)子路徑(AB,BC,CD)的時(shí)間。如果你沒有顯式地對(duì)keyTimes進(jìn)行設(shè)置,則系統(tǒng)會(huì)默認(rèn)每條子路徑的時(shí)間為:ti=duration/(幀數(shù)),即每條子路徑的duration相等
keyFA.keyTimes = @[@(0.0),@(0.5),@(0.9),@(2)];
//動(dòng)畫總時(shí)間
keyFA.duration = 5.0f;
//重復(fù)次數(shù),小于0無限重復(fù)
keyFA.repeatCount = 10;
/*
這個(gè)屬性用以指定時(shí)間函數(shù),類似于運(yùn)動(dòng)的加速度
kCAMediaTimingFunctionLinear//線性
kCAMediaTimingFunctionEaseIn//淡入
kCAMediaTimingFunctionEaseOut//淡出
kCAMediaTimingFunctionEaseInEaseOut//淡入淡出
kCAMediaTimingFunctionDefault//默認(rèn)
*/
keyFA.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
/*
fillMode的作用就是決定當(dāng)前對(duì)象過了非active時(shí)間段的行為. 比如動(dòng)畫開始之前,動(dòng)畫結(jié)束之后。如果是一個(gè)動(dòng)畫CAAnimation,則需要將其removedOnCompletion設(shè)置為NO,要不然fillMode不起作用.
下面來講各個(gè)fillMode的意義
kCAFillModeRemoved 這個(gè)是默認(rèn)值,也就是說當(dāng)動(dòng)畫開始前和動(dòng)畫結(jié)束后,動(dòng)畫對(duì)layer都沒有影響,動(dòng)畫結(jié)束后,layer會(huì)恢復(fù)到之前的狀態(tài)
kCAFillModeForwards 當(dāng)動(dòng)畫結(jié)束后,layer會(huì)一直保持著動(dòng)畫最后的狀態(tài)
kCAFillModeBackwards 這個(gè)和kCAFillModeForwards是相對(duì)的,就是在動(dòng)畫開始前,你只要將動(dòng)畫加入了一個(gè)layer,layer便立即進(jìn)入動(dòng)畫的初始狀態(tài)并等待動(dòng)畫開始.你可以這樣設(shè)定測試代碼,將一個(gè)動(dòng)畫加入一個(gè)layer的時(shí)候延遲5秒執(zhí)行.然后就會(huì)發(fā)現(xiàn)在動(dòng)畫沒有開始的時(shí)候,只要?jiǎng)赢嫳患尤肓薼ayer,layer便處于動(dòng)畫初始狀態(tài)
kCAFillModeBoth 理解了上面兩個(gè),這個(gè)就很好理解了,這個(gè)其實(shí)就是上面兩個(gè)的合成.動(dòng)畫加入后開始之前,layer便處于動(dòng)畫初始狀態(tài),動(dòng)畫結(jié)束后layer保持動(dòng)畫最后的狀態(tài).
//添加動(dòng)畫
*/
keyFA.fillMode = kCAFillModeForwards;
/*
在關(guān)鍵幀動(dòng)畫中還有一個(gè)非常重要的參數(shù),那便是calculationMode,計(jì)算模式.該屬性決定了物體在每個(gè)子路徑下是跳著走還是勻速走,跟timeFunctions屬性有點(diǎn)類似
其主要針對(duì)的是每一幀的內(nèi)容為一個(gè)座標(biāo)點(diǎn)的情況,也就是對(duì)anchorPoint 和 position 進(jìn)行的動(dòng)畫.當(dāng)在平面座標(biāo)系中有多個(gè)離散的點(diǎn)的時(shí)候,可以是離散的,也可以直線相連后進(jìn)行插值計(jì)算,也可以使用圓滑的曲線將他們相連后進(jìn)行插值計(jì)算. calculationMode目前提供如下幾種模式
kCAAnimationLinear calculationMode的默認(rèn)值,表示當(dāng)關(guān)鍵幀為座標(biāo)點(diǎn)的時(shí)候,關(guān)鍵幀之間直接直線相連進(jìn)行插值計(jì)算;
kCAAnimationDiscrete 離散的,就是不進(jìn)行插值計(jì)算,所有關(guān)鍵幀直接逐個(gè)進(jìn)行顯示;
kCAAnimationPaced 使得動(dòng)畫均勻進(jìn)行,而不是按keyTimes設(shè)置的或者按關(guān)鍵幀平分時(shí)間,此時(shí)keyTimes和timingFunctions無效;
kCAAnimationCubic 對(duì)關(guān)鍵幀為座標(biāo)點(diǎn)的關(guān)鍵幀進(jìn)行圓滑曲線相連后插值計(jì)算,對(duì)于曲線的形狀還可以通過tensionValues,continuityValues,biasValues來進(jìn)行調(diào)整自定義,這里的數(shù)學(xué)原理是Kochanek–Bartels spline,這里的主要目的是使得運(yùn)行的軌跡變得圓滑;
kCAAnimationCubicPaced 看這個(gè)名字就知道和kCAAnimationCubic有一定聯(lián)系,其實(shí)就是在kCAAnimationCubic的基礎(chǔ)上使得動(dòng)畫運(yùn)行變得均勻,就是系統(tǒng)時(shí)間內(nèi)運(yùn)動(dòng)的距離相同,此時(shí)keyTimes以及timingFunctions也是無效的.
*/
keyFA.calculationMode = kCAAnimationPaced;
//旋轉(zhuǎn)的模式,auto就是沿著切線方向動(dòng),autoReverse就是轉(zhuǎn)180度沿著切線動(dòng)
keyFA.rotationMode = kCAAnimationRotateAuto;
//結(jié)束后是否移除動(dòng)畫
keyFrameAnimation.removedOnCompletion = NO;
//添加動(dòng)畫
[self.redView.layer addAnimation:keyFA forKey:@""];
}
這里有個(gè)泡泡動(dòng)畫的demo,結(jié)合了貝塞爾曲線和幀動(dòng)畫,很精致
https://github.com/bnb173yjx/BubbleAnimationDemo