iOS動畫專題·UIView二維形變更畫與CAAnimation核心動畫(transform動畫,基礎,關鍵幀,組動畫,路徑動畫,貝塞爾曲線)

1. iOS動畫

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

2. UIView動畫

設置UIView形變更畫有兩種常見用到的屬性,.frame.transform,因此有的人也能夠分別稱之爲:bash

  • ① frame動畫
  • ② transform動畫

這兩種動畫只須要在動畫語法中適當的位置,基於UIView和CALayer的屬性設置變化值便可。這種動畫,不須要 調用核心動畫CAAnimation裏面的專用類和API。ide

其中,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。ui

  • (2) 通常在實際開發中都是平移,旋轉,縮放組合使用。this

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

下面是CALayer的一些屬性介紹atom

//寬度和高度
@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;
};
複製代碼

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

由於最後一列老是是(0,0,1),因此有用的信息就是前面兩列。對一個view進行仿射變化就至關於對view上的每一個點作一個乘法,結果就是:

a表示x水平方向的縮放,tx表示x水平方向的偏移 d表示y垂直方向的縮放,ty表示y垂直方向的偏移 若是b和c不爲零的話,那麼視圖確定發生了旋轉,旋轉角度這樣計算:tan(angle) = b / a

若是這樣:

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

  • CGAffineTransform操做API
//還原
CGAffineTransformIdentity

//位移仿射  ---- 理解爲平移 (CGFloat tx,CGFloat ty) 
CGAffineTransformMakeTranslation 
CGAffineTransformTranslate 
//旋轉仿射 ---- 理解爲旋轉 (CGFloat angle)
CGAffineTransformMakeRotation
CGAffineTransformRotate 
//縮放仿射  --- 理解縮放大小 (CGFloat sx, CGFloat sy)
CGAffineTransformMakeScale 
CGAffineTransformScale
複製代碼

CGAffineTransform操做的數學本質

  • CGPoint轉換公式

  • 矩陣乘法運算原理演示

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"];
}
複製代碼
相關文章
相關標籤/搜索