iOS-進(jìn)階整理13 - 貝塞爾曲線和幀動(dòng)畫結(jié)合

一、貝塞爾曲線

參考來自下面的文章,這篇文章被轉(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

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 本文只要描述了iOS中的Core Animation(核心動(dòng)畫:隱式動(dòng)畫、顯示動(dòng)畫)、貝塞爾曲線、UIVie...
    GitHubPorter閱讀 3,736評(píng)論 7 11
  • 談?wù)勜惾麪柷€ 最近在做項(xiàng)目的時(shí)候,需要用到一個(gè)動(dòng)畫,非常簡單的動(dòng)畫,簡單到就是直接對(duì)一個(gè)View做平移… 然而雖...
    雨潤聽潮閱讀 6,275評(píng)論 1 16
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,688評(píng)論 6 30
  • 概覽 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你...
    Yiart閱讀 3,960評(píng)論 3 34
  • 最近在做項(xiàng)目的時(shí)候,需要用到一個(gè)動(dòng)畫,非常簡單的動(dòng)畫,簡單到就是直接對(duì)一個(gè)View做平移... 然而雖然動(dòng)畫簡單,...
    IAMDAEMON閱讀 4,406評(píng)論 12 69

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