天天看點

iOS 動畫專題(UIView二維形變動畫與CAAnimation核心動畫)

文章目錄

    • 1. iOS動畫
    • 2. UIView動畫
        • 2.1 設定UIView動畫的兩種文法形式
        • 2.2 設定屬性形變動畫的兩種類型
        • 2.3 與動畫相關的屬性
            • 2.3.1 UIView與動畫相關的屬性--與CGAffineTransform對應
        • 2.4 管理二維形變和三維形變的封裝類:CGAffineTransform與CATransform3D
            • 2.4.1 CGAffineTransform操作API
        • CGAffineTransform操作API
            • 2.4.2 CATransform3D操作API
            • 2.4.3 CATransform3D與CGAffineTransform互相轉換API
        • 2.5 “組合動畫” 與 CGAffineTransformConcat
            • 2.5.1 連接配接設定多個屬性組合成一個動畫
            • 2.5.2 利用CGAffineTransformConcat設定組合動畫
        • 2.6 動畫後将屬性還原
        • 2.7 注意點: transform對frame的影響
    • 3. CAAnimation核心動畫
        • 3.1 設定動畫的一種文法形式
        • 3.2 CAAnimation繼承結構
        • 3.3 CAAnimation類的屬性
        • 3.4 幾個重要屬性值
            • removedOnCompletion屬性值
            • fillMode屬性值
            • timingFunction屬性值
    • 4. CABasicAnimation
        • 4.1 特别屬性說明:
        • 4.2 keyPath可以是哪些值
        • 4.3 舉例
    • 5. CAKeyframeAnimation關鍵幀動畫
        • 5.1 參數數組形式
        • 5.2 path形式
    • 6. 組動畫
        • 6.1 組動畫
        • 6.2 示例
    • 7. 貝塞爾曲線
        • 7.1 CGMutablePathRef
        • 7.2 UIBezierPath

1. iOS動畫

總的來說,從涉及類的形式來看,iOS動畫有:基于UIView的仿射形變動畫,基于CAAnimation及其子類的動畫,基于CG的動畫。這篇文章着重總結前兩種動畫。

2. UIView動畫

設定UIView形變動畫有兩種常見用到的屬性,.frame,.transform,是以有的人也可以分别稱之為:

① frame動畫

② transform動畫

這兩種動畫隻需要在動畫文法中适當的位置,基于UIView和CALayer的屬性設定變化值即可。這種動畫,不需要 調用核心動畫CAAnimation裡面的專用類和API。

其中,frame動畫設定方式有限,必須确切地制定形變前後的frame,平移還好,特别是 旋轉 的時候,隻能通過數學知識計算出新的frame。這就得不償失了。是以,更多的時候,當涉及一些frame,bounds,center的改變或是形變的時候可以用transform來取代frame。

2.1 設定UIView動畫的兩種文法形式

begin — commit

//偏移動畫
  [UIView beginAnimations:@"move" context:nil];  
  [UIView setAnimationDuration:2];  
  [UIView setAnimationDelegate:self];  
  imageContainView.frame = CGRectMake(80, 80, 200, 200);  
  [label1 setBackgroundColor:[UIColor yellowColor]];  
  [label1 setTextColor:[UIColor redColor]];  
  [UIView commitAnimations]; 
           

animations block

//縮放動畫
  view.transform = CGAffineTransformIdentity;
  [UIView animateWithDuration:1.0f animations:^{
     view.transform = CGAffineTransformMakeScale(2.0f, 2.0f);
  }];
           

2.2 設定屬性形變動畫的兩種類型

UIView的 CGAffineTransform 類型屬性:animatedView.transform

一般是View的旋轉,拉伸移動等屬性,是二維的,通常使用都是字首CGAffineTransform的類。

CGAffineTransform transform = CGAffineTransformScale(imageContainView.transform, 1.2, 1.2); 
[UIView beginAnimations: @"scale"context: nil]; 
[UIView setAnimationDuration: 2];
[UIView setAnimationDelegate: self];
[imageView setTransform: transform]; 
[UIView commitAnimations];
           

CALayer的CATransform3D 類型屬性:animaView.layer.transform

通過 .layer.transform 可以在3D模式下面的變化,通常使用的都是字首為CATransform3D的類。

imageView.layer.transform =  CATransform3DIdentity;
[UIView animateWithDuration:1.0f animations:^{
      imageView.layer.transform = CATransform3DMakeScale(2.0, 2.0, 1.0);
}];
           

2.3 與動畫相關的屬性

2.3.1 UIView與動畫相關的屬性–與CGAffineTransform對應

下面是UIView的一些屬性介紹

@property(nonatomic) CGRect            frame;
@property(nonatomic) CGRect            bounds;      // default bounds is zero origin, frame size. animatable
@property(nonatomic) CGPoint           center;      // center is center of frame. animatable
@property(nonatomic) CGAffineTransform transform;   // default is CGAffineTransformIdentity. animatable
@property(nonatomic) CGFloat           contentScaleFactor NS_AVAILABLE_IOS(4_0);

@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled __TVOS_PROHIBITED;   // default is NO
@property(nonatomic,getter=isExclusiveTouch) BOOL       exclusiveTouch __TVOS_PROHIBITED;         // default is NO
           

在實際開發中,使用場景:

(1) 當涉及一些frame, bounds, center的改變或是形變的時候可以用 transform 來取代 frame。

(2) 一般在實際開發中都是平移,旋轉,縮放組合使用。

######2.3.2 CALayer與動畫相關的屬性–與CATransform3D對應

下面是CALayer的一些屬性介紹

//寬度和高度
@property CGRect bounds;

//位置(預設指中點,具體由anchorPoint決定)
@property CGPoint position;

//錨點(x,y的範圍都是0-1),決定了position的含義
@property CGPoint anchorPoint;

//背景顔色(CGColorRef類型)
@property CGColorRef backgroundColor;

//形變屬性
@property CATransform3D transform;

//邊框顔色(CGColorRef類型)
@property CGColorRef  borderColor;

//邊框寬度
@property CGFloat borderWidth;

//圓角半徑
@property CGFloat cornerRadius;

//内容(比如設定為圖檔CGImageRef)
@property(retain) id contents;
           

2.4 管理二維形變和三維形變的封裝類:CGAffineTransform與CATransform3D

2.4.1 CGAffineTransform操作API

CGAffineTransform結構體定義

struct CGAffineTransform {
  CGFloat a, b, c, d;
  CGFloat tx, ty;
};
           

它其實表示的是一個矩陣:

iOS 動畫專題(UIView二維形變動畫與CAAnimation核心動畫)

因為最後一列總是是(0,0,1),是以有用的資訊就是前面兩列。對一個view進行仿射變化就相當于對view上的每個點做一個乘法,結果就是:

iOS 動畫專題(UIView二維形變動畫與CAAnimation核心動畫)

a表示x水準方向的縮放,tx表示x水準方向的偏移

d表示y垂直方向的縮放,ty表示y垂直方向的偏移

如果b和c不為零的話,那麼視圖肯定發生了旋轉,旋轉角度這樣計算:tan(angle) = b / a

如果這樣:

iOS 動畫專題(UIView二維形變動畫與CAAnimation核心動畫)

這個就是沒有變化的最初的樣子。

CGAffineTransform操作API

//還原
CGAffineTransformIdentity

//位移仿射  ---- 了解為平移 (CGFloat tx,CGFloat ty) 
CGAffineTransformMakeTranslation 
CGAffineTransformTranslate 
//旋轉仿射 ---- 了解為旋轉 (CGFloat angle)
CGAffineTransformMakeRotation
CGAffineTransformRotate 
//縮放仿射  --- 了解縮放大小 (CGFloat sx, CGFloat sy)
CGAffineTransformMakeScale 
CGAffineTransformScale
           

CGAffineTransform操作的數學本質

CGPoint轉換公式

iOS 動畫專題(UIView二維形變動畫與CAAnimation核心動畫)

矩陣乘法運算原理示範

iOS 動畫專題(UIView二維形變動畫與CAAnimation核心動畫)

2.4.2 CATransform3D操作API

//還原
 CATransform3DIdentity

 //位移3D仿射  ==> (CGFloat tx, CGFloat ty, CGFloat tz)
CATransform3DMakeTranslation
CATransform3DTranslation        
//旋轉3D仿射 ==> (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeRotation
CATransform3DRotation  
//縮放3D仿射 ==>  (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale
CATransform3DScale
//疊加3D仿射效果
CATransform3DConcat    
//仿射基礎3D方法,可以直接做效果疊加
CGAffineTransformMake (sx,shx,shy,sy,tx,ty)
//檢查是否有做過仿射3D效果  == ((CATransform3D t))
CATransform3DIsIdentity(transform)
//檢查2個3D仿射效果是否相同
CATransform3DEqualToTransform(transform1,transform2)
//3D仿射效果反轉(反效果,比如原來擴大,就變成縮小)
CATransform3DInvert(transform)
           

2.4.3 CATransform3D與CGAffineTransform互相轉換API

//将一個CGAffinrTransform轉化為CATransform3D
CATransform3D CATransform3DMakeAffineTransform (CGAffineTransform m);
//判斷一個CATransform3D是否可以轉換為CAAffineTransformbool 
CATransform3DIsAffine (CATransform3D t);
//将CATransform3D轉換為CGAffineTransform
CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);
           

2.5 “組合動畫” 與 CGAffineTransformConcat

2.5.1 連接配接設定多個屬性組合成一個動畫

連接配接設定兩個以上屬性的動畫,可以先調用含有 formMake 的API,然後再調用隻含 form 的API。例如,這樣:

alertView.transform = CGAffineTransformMakeScale(.25, .25);
alertView.transform = CGAffineTransformTranslate(alertView.transform, 0, 600);
           

2.5.2 利用CGAffineTransformConcat設定組合動畫

另外,可以直接利用 CGAffineTransformConcat 來組合多種含有 formMake 的形變API。

CGAffineTransform viewTransform = CGAffineTransformConcat(CGAffineTransformMakeScale(.25, .25), CGAffineTransformMakeTranslation(0, 600));
alertView.transform = viewTransform;
           

關于組合3D形變也有相應的API — CATransform3DConcat,關于3D形變下一篇會專門介紹。

CGAffineTransformConcat 組合多種形變動畫小例子

- (void)viewDidAppear: (BOOL)animated {
    ///  初始化動畫開始前label的位置
    CGFloat offset = label1.frame.size.height * 0.5;

    label1.transform = CGAffineTransformConcat(
      CGAffineTransformMakeScale(0, 0),
      CGAffineTransformTranslate(0, -offset)
    );
    label1.alpha = 0;
    [UIView animateWithDuration: 3. animations: ^ {
        ///  還原label1的變換狀态并形變和偏移label2
        label1.transform = CGAffineTransformIdentifier;
        label1.transform = CGAffineTransformConcat(
          CGAffineTransformMakeScale(0, 0),
          CGAffineTransformTranslate(0, offset)
        );
        label1.alpha = 1;
        label2.alpha = 0;
    }];
}
           

組合變換的本質

CGAffineTransformConcat的數學本質是将括号内代表的若幹變換的系數矩陣進行相乘。

另一種組合變換

基于已有的CGAffineTransform連續追加新的CGAffineTransform:

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, 0.5f, 0.5f);
transform = CGAffineTransformRotate(transform, 30.0f/180.0f*M_PI);
transform = CGAffineTransformTranslate(transform, 200.0f, 0.0f);
layerView.layer.affineTransform = transform;
           

2.6 動畫後将屬性還原

當我們改變過一個view.transform屬性或者view.layer.transform的時候需要恢複預設狀态的話,記得先把他 們重置為:

view.transform = CGAffineTransformIdentity;
view.layer.transform = CATransform3DIdentity;
           

2.7 注意點: transform對frame的影響

官方文檔上關于transform屬性的說明:

Changes to this property can be animated. However, if the transform

property contains a non-identity transform, the value of the frame

property is undefined and should not be modified. In that case, you

can reposition the view using the center property and adjust the size

using the bounds property instead.

如果在程式中改變了某個控件的transform,那麼請不要使用這個控件的frame計算 子控件 的布局,應該使用bounds+center代替。

3. CAAnimation核心動畫

CAAnimation——所有動畫對象的父類

3.1 設定動畫的一種文法形式

addAnimation

/**
 *  抖動效果
 */
-(void)shakeAnimation{
    CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];//在這裡@"transform.rotation"==@"transform.rotation.z"
    NSValue *value1 = [NSNumber numberWithFloat:-M_PI/180*4];
    NSValue *value2 = [NSNumber numberWithFloat:M_PI/180*4];
    NSValue *value3 = [NSNumber numberWithFloat:-M_PI/180*4];
    anima.values = @[value1,value2,value3];
    anima.repeatCount = MAXFLOAT;

    [_demoView.layer addAnimation:anima forKey:@"shakeAnimation"];
}
           

3.2 CAAnimation繼承結構

CAAnimation{
     CAPropertyAnimation{
            CABasicAnimation{
                    CASpringAnimation
            }
            CAKeyframeAnimation
     }
     CATransition   
     CAAnimationGroup
}
           

是所有動畫對象的父類,負責控制動畫的持續時間和速度,是個抽象類,不能直接使用,應該使用它具體的子類

3.3 CAAnimation類的屬性

帶*号代表來自CAMediaTiming協定的屬性)

  • *duration:動畫的持續時間
  • *repeatCount:重複次數,無限循環可以設定HUGE_VALF或者MAXFLOAT
  • *repeatDuration:重複時間
  • removedOnCompletion:預設為YES,代表動畫執行完畢後就從圖層上移除,圖形會恢複到動畫執行前的狀态。如果想讓圖層保持顯示動畫執行後的狀态,那就設定為NO,不過還要設定fillMode為kCAFillModeForwards
  • *fillMode:決定目前對象在非active時間段的行為。比如動畫開始之前或者動畫結束之後
  • *beginTime:可以用來設定動畫延遲執行時間,若想延遲2s,就設定為
  • CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的目前時間
  • timingFunction:速度控制函數,控制動畫運作的節奏
  • delegate:動畫代理

3.4 幾個重要屬性值

removedOnCompletion屬性值

CAAnimation——動畫填充模式

預設為YES,代表動畫執行完畢後就從圖層上移除,圖形會恢複到動畫執行前的狀态。如果想讓圖層保持顯示動畫執行後的狀态,那就設定為NO,不過還要設定fillMode為kCAFillModeForwards

fillMode屬性值

CAAnimation——控制恢複到動畫執行前

要想fillMode有效,最好設定removedOnCompletion = NO

  • kCAFillModeRemoved

    這個是預設值,也就是說當動畫開始前和動畫結束後,動畫對layer都沒有影響,動畫結束後,layer會恢複到之前的狀态

  • kCAFillModeForwards 當動畫結束後,layer會一直保持着動畫最後的狀态
  • kCAFillModeBackwards

    在動畫開始前,隻需要将動畫加入了一個layer,layer便立即進入動畫的初始狀态并等待動畫開始。

  • kCAFillModeBoth

    這個其實就是上面兩個的合成.動畫加入後開始之前,layer便處于動畫初始狀态,動畫結束後layer保持動畫最後的狀态

如果 fillMode = kCAFillModeForwards 同時 removedOnComletion = NO ,那麼在動畫執行完畢後,圖層會保持顯示動畫執行後的狀态。但在實質上,圖層的屬性值還是動畫執行前的初始值,并沒有真正被改變。

timingFunction屬性值

CAAnimation——動畫速度控制函數
  • kCAMediaTimingFunctionLinear(線性):勻速,給你一個相對靜态的感覺
  • kCAMediaTimingFunctionEaseIn(漸進):動畫緩慢進入,然後加速離開
  • kCAMediaTimingFunctionEaseOut(漸出):動畫全速進入,然後減速的到達目的地
  • kCAMediaTimingFunctionEaseInEaseOut(漸進漸出):動畫緩慢的進入,中間加速,然後減速的到達目的地。這個是預設的動畫行為。

4. CABasicAnimation

基本動畫,是CAPropertyAnimation的子類

4.1 特别屬性說明:

  • keyPath: 要改變的屬性名稱(傳字元串)
  • fromValue: keyPath相應屬性的初始值
  • toValue: keyPath相應屬性的結束值

4.2 keyPath可以是哪些值

CATransform3D{
    //rotation旋轉
    transform.rotation.x
    transform.rotation.y
    transform.rotation.z

    //scale縮放
    transform.scale.x
    transform.scale.y
    transform.scale.z

    //translation平移
    transform.translation.x
    transform.translation.y
    transform.translation.z
}

CGPoint{
    position
    position.x
    position.y
}

CGRect{
    bounds
    bounds.size
    bounds.size.width
    bounds.size.height

    bounds.origin
    bounds.origin.x
    bounds.origin.y
}

property{
    opacity
    backgroundColor
    cornerRadius
    borderWidth
    contents

    Shadow{
        shadowColor
        shadowOffset
        shadowOpacity
        shadowRadius
    }
}
           

4.3 舉例

縮放動畫 – transform.scale

//心髒縮放動畫
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; //選中的這個keyPath就是縮放
    scaleAnimation.fromValue = [NSNumber numberWithDouble:0.5]; //一開始時是0.5的大小
    scaleAnimation.toValue = [NSNumber numberWithDouble:1.5];  //結束時是1.5的大小
    scaleAnimation.duration = 1; //設定時間
    scaleAnimation.repeatCount = MAXFLOAT; //重複次數
    [_heartImageView.layer addAnimation:scaleAnimation forKey:@"CQScale"]; //添加動畫
           

旋轉動畫 – transform.rotation.z

//風車旋轉動畫
    CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.fromValue = [NSNumber numberWithDouble:0.f];
    rotationAnimation.toValue = [NSNumber numberWithDouble:2 * M_PI];
    rotationAnimation.duration = 2.f;
    rotationAnimation.repeatCount = MAXFLOAT;
    [_fengcheImageView.layer addAnimation:rotationAnimation forKey:@"CQRotation"];
           

平移動畫 – position.x/position.y

//平移動畫
    CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    positionAnimation.fromValue = [NSNumber numberWithDouble:0.f];
    positionAnimation.toValue = [NSNumber numberWithDouble:SCREEN_WIDTH];
    positionAnimation.duration = 2;
    positionAnimation.repeatCount = MAXFLOAT;
    [_arrowImageView.layer addAnimation:positionAnimation forKey:@"CQPosition"];
           

5. CAKeyframeAnimation關鍵幀動畫

5.1 參數數組形式

//根據values移動的動畫
    CAKeyframeAnimation *catKeyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    CGPoint originalPoint = self.catImageView.layer.frame.origin;
    CGFloat distance =  50;
    NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(originalPoint.x + distance, originalPoint.y + distance)];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(originalPoint.x + 2 * distance, originalPoint.y + distance)];
    NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(originalPoint.x + 2 * distance, originalPoint.y +  2 * distance)];
    NSValue *value4 = [NSValue valueWithCGPoint:originalPoint];
    catKeyAnimation.values = @[value4, value1, value2, value3, value4];
    catKeyAnimation.duration = 2;
    catKeyAnimation.repeatCount = MAXFLOAT;
    catKeyAnimation.removedOnCompletion = NO;
    [self.catImageView.layer addAnimation:catKeyAnimation forKey:nil];
           

5.2 path形式

//指定path
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 200, 200, 200)];
    //指定path的動畫
    UIBezierPath *path2 = [UIBezierPath bezierPath];
    [path2 moveToPoint:CGPointMake(100, 100)];
    [path2 addLineToPoint:CGPointMake(100, 200)];
    [path2 addLineToPoint:CGPointMake(200, 200)];
    [path2 addLineToPoint:CGPointMake(200, 100)];
    [path2 addLineToPoint:CGPointMake(100, 100)];
    CAKeyframeAnimation *penguinAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    penguinAnimation.path = path2.CGPath;
    penguinAnimation.duration = 2;
    penguinAnimation.repeatCount = MAXFLOAT;
    penguinAnimation.removedOnCompletion = NO;
    [self.penguinImageView.layer addAnimation:penguinAnimation forKey:nil];
           

6. 組動畫

6.1 組動畫

上面單一動畫的情況在實際開發中實際比較少,更多的時候是組合這些動畫:建立不同類型的動畫對象,設定好它們的參數,然後把這些動畫對象存進數組,傳進組動畫對象的animations屬性中去。

6.2 示例

//建立組動畫
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    animationGroup.duration = 3;
    animationGroup.repeatCount = MAXFLOAT;
    animationGroup.removedOnCompletion = NO;
    /* beginTime 可以分别設定每個動畫的beginTime來控制組動畫中每個動畫的觸發時間,時間不能夠超過動畫的時間,預設都為0.f */

    //縮放動畫
    CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
    animation1.values = @[[NSNumber numberWithFloat:1.0],[NSNumber numberWithFloat:0.5],[NSNumber numberWithFloat:1.5],[NSNumber numberWithFloat:1.0]];
    animation1.beginTime = 0.f;

    //按照圓弧移動動畫
    CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath moveToPoint:CGPointMake(300, 200)];
    [bezierPath addQuadCurveToPoint:CGPointMake(200, 300) controlPoint:CGPointMake(300, 300)];
    [bezierPath addQuadCurveToPoint:CGPointMake(100, 200) controlPoint:CGPointMake(100, 300)];
    [bezierPath addQuadCurveToPoint:CGPointMake(200, 100) controlPoint:CGPointMake(100, 100)];
    [bezierPath addQuadCurveToPoint:CGPointMake(300, 200) controlPoint:CGPointMake(300, 100)];
    animation2.path = bezierPath.CGPath;
    animation2.beginTime = 0.f;

    //透明度動畫
    CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation3.fromValue = [NSNumber numberWithDouble:0.0];
    animation3.toValue = [NSNumber numberWithDouble:1.0];
    animation3.beginTime = 0.f;

    //添加組動畫
    animationGroup.animations = @[animation1, animation2,animation3];
    [_penguinImageView.layer addAnimation:animationGroup forKey:nil];
           

7. 貝塞爾曲線

前面關鍵幀動畫章節提到了貝塞爾曲線,這個曲線很有用,在iOS開發中有兩種形式可用:CGMutablePathRef和UIBezierPath,均可以通過制定控制點數組的形式唯一确定曲線,也可以通過矩形内切橢圓唯一确定曲線。下面是兩者的例子:

7.1 CGMutablePathRef

通過 關鍵點曲線連接配接 唯一确定

// 貝塞爾曲線關鍵幀
    // 設定路徑, 繪制貝塞爾曲線
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 200, 200); // 起始點
    CGPathAddCurveToPoint(path, NULL, 100, 300, 300, 500, 200, 600);
    // CGPathAddCurveToPoint(path, NULL, 控制點1.x, 控制點1.y, 控制點2.x, 控制點2.y, 終點.x, 終點.y);
    // 設定path屬性
    keyframeAnimation.path = path;
    CGPathRelease(path);

    // 設定其他屬性
    keyframeAnimation.duration = 4;
    keyframeAnimation.beginTime = CACurrentMediaTime() + 1; // 設定延遲2秒執行, 不設定這個屬性, 預設直接執行
    // 3. 添加動畫到圖層, 會自動執行
    [_layer addAnimation:keyframeAnimation forKey:@"GGKeyframeAnimation"];
           

7.2 UIBezierPath

通過 矩形内切橢圓 唯一确定

CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(SCREEN_WIDTH/2-100, SCREEN_HEIGHT/2-100, 200, 200)];
    anima.path = path.CGPath;
    anima.duration = 2.0f;
    [_demoView.layer addAnimation:anima forKey:@"pathAnimation"];
           

通過 關鍵點直線連接配接 唯一确定

-(void)pathAnimation2{

    //建立path
    UIBezierPath *path = [UIBezierPath bezierPath];
    //設定線寬
    path.lineWidth = 3;
    //線條拐角
    path.lineCapStyle = kCGLineCapRound;
    //終點處理
    path.lineJoinStyle = kCGLineJoinRound;
    //多條直線
    [path moveToPoint:(CGPoint){0, SCREEN_HEIGHT/2-50}];
    [path addLineToPoint:(CGPoint){SCREEN_WIDTH/3, SCREEN_HEIGHT/2-50}];
    [path addLineToPoint:(CGPoint){SCREEN_WIDTH/3, SCREEN_HEIGHT/2+50}];
    [path addLineToPoint:(CGPoint){SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2+50}];
    [path addLineToPoint:(CGPoint){SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2-50}];
    [path addLineToPoint:(CGPoint){SCREEN_WIDTH, SCREEN_HEIGHT/2-50}];
//    [path closePath];

    CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    anima.path = path.CGPath;
    anima.duration = 2.0f;
    anima.fillMode = kCAFillModeForwards;
    anima.removedOnCompletion = NO;
    anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [_demoView.layer addAnimation:anima forKey:@"pathAnimation"];
}
           

繼續閱讀