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

文章目錄

  1. iOS動(dòng)畫

  2. UIView動(dòng)畫
    2.1 設(shè)置UIView動(dòng)畫的兩種語法形式
    2.2 設(shè)置屬性形變動(dòng)畫的兩種類型
    2.3 與動(dòng)畫相關(guān)的屬性
    2.3.1 UIView與動(dòng)畫相關(guān)的屬性--與CGAffineTransform對(duì)應(yīng)
    2.4 管理二維形變和三維形變的封裝類:CGAffineTransform與CATransform3D
    2.4.1 CGAffineTransform操作API
    CGAffineTransform操作API
    2.4.2 CATransform3D操作API
    2.4.3 CATransform3D與CGAffineTransform相互轉(zhuǎn)換API
    2.5 “組合動(dòng)畫” 與 CGAffineTransformConcat
    2.5.1 連接設(shè)置多個(gè)屬性組合成一個(gè)動(dòng)畫
    2.5.2 利用CGAffineTransformConcat設(shè)置組合動(dòng)畫
    2.6 動(dòng)畫后將屬性還原
    2.7 注意點(diǎn): transform對(duì)frame的影響

  3. CAAnimation核心動(dòng)畫
    3.1 設(shè)置動(dòng)畫的一種語法形式
    3.2 CAAnimation繼承結(jié)構(gòu)
    3.3 CAAnimation類的屬性
    3.4 幾個(gè)重要屬性值
    removedOnCompletion屬性值
    fillMode屬性值
    timingFunction屬性值

  4. CABasicAnimation
    4.1 特別屬性說明:
    4.2 keyPath可以是哪些值
    4.3 舉例

  5. CAKeyframeAnimation關(guān)鍵幀動(dòng)畫
    5.1 參數(shù)數(shù)組形式
    5.2 path形式

  6. 組動(dòng)畫
    6.1 組動(dòng)畫
    6.2 示例

  7. 貝塞爾曲線
    7.1 CGMutablePathRef
    7.2 UIBezierPath

  8. iOS動(dòng)畫
    總的來說,從涉及類的形式來看,iOS動(dòng)畫有:基于UIView的仿射形變動(dòng)畫,基于CAAnimation及其子類的動(dòng)畫,基于CG的動(dòng)畫。這篇文章著重總結(jié)前兩種動(dòng)畫。

  9. UIView動(dòng)畫
    設(shè)置UIView形變動(dòng)畫有兩種常見用到的屬性,.frame,.transform,所以有的人也可以分別稱之為:

① frame動(dòng)畫
② transform動(dòng)畫

這兩種動(dòng)畫只需要在動(dòng)畫語法中適當(dāng)?shù)奈恢茫赨IView和CALayer的屬性設(shè)置變化值即可。這種動(dòng)畫,不需要 調(diào)用核心動(dòng)畫CAAnimation里面的專用類和API。

其中,frame動(dòng)畫設(shè)置方式有限,必須確切地制定形變前后的frame,平移還好,特別是 旋轉(zhuǎn) 的時(shí)候,只能通過數(shù)學(xué)知識(shí)計(jì)算出新的frame。這就得不償失了。所以,更多的時(shí)候,當(dāng)涉及一些frame,bounds,center的改變或是形變的時(shí)候可以用transform來取代frame。

2.1 設(shè)置UIView動(dòng)畫的兩種語法形式
begin — commit

//偏移動(dòng)畫
[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];
1
2
3
4
5
6
7
8
animations block

//縮放動(dòng)畫
view.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:1.0f animations:^{
view.transform = CGAffineTransformMakeScale(2.0f, 2.0f);
}];
1
2
3
4
5
2.2 設(shè)置屬性形變動(dòng)畫的兩種類型
UIView的 CGAffineTransform 類型屬性:animatedView.transform
一般是View的旋轉(zhuǎn),拉伸移動(dòng)等屬性,是二維的,通常使用都是前綴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];
1
2
3
4
5
6
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);
}];
1
2
3
4
2.3 與動(dòng)畫相關(guān)的屬性
2.3.1 UIView與動(dòng)畫相關(guān)的屬性–與CGAffineTransform對(duì)應(yīng)
下面是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
2
3
4
5
6
7
8
在實(shí)際開發(fā)中,使用場景:

(1) 當(dāng)涉及一些frame, bounds, center的改變或是形變的時(shí)候可以用 transform 來取代 frame。
(2) 一般在實(shí)際開發(fā)中都是平移,旋轉(zhuǎn),縮放組合使用。

2.3.2 CALayer與動(dòng)畫相關(guān)的屬性–與CATransform3D對(duì)應(yīng)

下面是CALayer的一些屬性介紹

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

//位置(默認(rèn)指中點(diǎn),具體由anchorPoint決定)
@property CGPoint position;

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

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

//形變屬性
@property CATransform3D transform;

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

//邊框?qū)挾?br> @property CGFloat borderWidth;

//圓角半徑
@property CGFloat cornerRadius;

//內(nèi)容(比如設(shè)置為圖片CGImageRef)
@property(retain) id contents;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2.4 管理二維形變和三維形變的封裝類:CGAffineTransform與CATransform3D
2.4.1 CGAffineTransform操作API
CGAffineTransform結(jié)構(gòu)體定義

struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
1
2
3
4
5
它其實(shí)表示的是一個(gè)矩陣:

因?yàn)樽詈笠涣锌偸鞘?0,0,1),所以有用的信息就是前面兩列。對(duì)一個(gè)view進(jìn)行仿射變化就相當(dāng)于對(duì)view上的每個(gè)點(diǎn)做一個(gè)乘法,結(jié)果就是:

a表示x水平方向的縮放,tx表示x水平方向的偏移
d表示y垂直方向的縮放,ty表示y垂直方向的偏移
如果b和c不為零的話,那么視圖肯定發(fā)生了旋轉(zhuǎn),旋轉(zhuǎn)角度這樣計(jì)算:tan(angle) = b / a

如果這樣:

這個(gè)就是沒有變化的最初的樣子。

CGAffineTransform操作API
//還原
CGAffineTransformIdentity

//位移仿射 ---- 理解為平移 (CGFloat tx,CGFloat ty)
CGAffineTransformMakeTranslation
CGAffineTransformTranslate
//旋轉(zhuǎn)仿射 ---- 理解為旋轉(zhuǎn) (CGFloat angle)
CGAffineTransformMakeRotation
CGAffineTransformRotate
//縮放仿射 --- 理解縮放大小 (CGFloat sx, CGFloat sy)
CGAffineTransformMakeScale
CGAffineTransformScale
1
2
3
4
5
6
7
8
9
10
11
12
CGAffineTransform操作的數(shù)學(xué)本質(zhì)

CGPoint轉(zhuǎn)換公式

矩陣乘法運(yùn)算原理演示

2.4.2 CATransform3D操作API
//還原
CATransform3DIdentity

//位移3D仿射 ==> (CGFloat tx, CGFloat ty, CGFloat tz)
CATransform3DMakeTranslation
CATransform3DTranslation
//旋轉(zhuǎn)3D仿射 ==> (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeRotation
CATransform3DRotation
//縮放3D仿射 ==> (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale
CATransform3DScale
//疊加3D仿射效果
CATransform3DConcat
//仿射基礎(chǔ)3D方法,可以直接做效果疊加
CGAffineTransformMake (sx,shx,shy,sy,tx,ty)
//檢查是否有做過仿射3D效果 == ((CATransform3D t))
CATransform3DIsIdentity(transform)
//檢查2個(gè)3D仿射效果是否相同
CATransform3DEqualToTransform(transform1,transform2)
//3D仿射效果反轉(zhuǎn)(反效果,比如原來擴(kuò)大,就變成縮小)
CATransform3DInvert(transform)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2.4.3 CATransform3D與CGAffineTransform相互轉(zhuǎn)換API
//將一個(gè)CGAffinrTransform轉(zhuǎn)化為CATransform3D
CATransform3D CATransform3DMakeAffineTransform (CGAffineTransform m);
//判斷一個(gè)CATransform3D是否可以轉(zhuǎn)換為CAAffineTransformbool
CATransform3DIsAffine (CATransform3D t);
//將CATransform3D轉(zhuǎn)換為CGAffineTransform
CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);
1
2
3
4
5
6
2.5 “組合動(dòng)畫” 與 CGAffineTransformConcat
2.5.1 連接設(shè)置多個(gè)屬性組合成一個(gè)動(dòng)畫
連接設(shè)置兩個(gè)以上屬性的動(dòng)畫,可以先調(diào)用含有 formMake 的API,然后再調(diào)用只含 form 的API。例如,這樣:

alertView.transform = CGAffineTransformMakeScale(.25, .25);
alertView.transform = CGAffineTransformTranslate(alertView.transform, 0, 600);
1
2
2.5.2 利用CGAffineTransformConcat設(shè)置組合動(dòng)畫
另外,可以直接利用 CGAffineTransformConcat 來組合多種含有 formMake 的形變API。

CGAffineTransform viewTransform = CGAffineTransformConcat(CGAffineTransformMakeScale(.25, .25), CGAffineTransformMakeTranslation(0, 600));
alertView.transform = viewTransform;
1
2
關(guān)于組合3D形變也有相應(yīng)的API — CATransform3DConcat,關(guān)于3D形變下一篇會(huì)專門介紹。

CGAffineTransformConcat 組合多種形變動(dòng)畫小例子

  • (void)viewDidAppear: (BOOL)animated {
    /// 初始化動(dòng)畫開始前l(fā)abel的位置
    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的變換狀態(tài)并形變和偏移label2
    label1.transform = CGAffineTransformIdentifier;
    label1.transform = CGAffineTransformConcat(
    CGAffineTransformMakeScale(0, 0),
    CGAffineTransformTranslate(0, offset)
    );
    label1.alpha = 1;
    label2.alpha = 0;
    }];
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    組合變換的本質(zhì)
    CGAffineTransformConcat的數(shù)學(xué)本質(zhì)是將括號(hào)內(nèi)代表的若干變換的系數(shù)矩陣進(jìn)行相乘。

另一種組合變換
基于已有的CGAffineTransform連續(xù)追加新的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;
1
2
3
4
5
2.6 動(dòng)畫后將屬性還原
當(dāng)我們改變過一個(gè)view.transform屬性或者view.layer.transform的時(shí)候需要恢復(fù)默認(rèn)狀態(tài)的話,記得先把他 們重置為:

view.transform = CGAffineTransformIdentity;
view.layer.transform = CATransform3DIdentity;
1
2
2.7 注意點(diǎn): transform對(duì)frame的影響
官方文檔上關(guān)于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.

如果在程序中改變了某個(gè)控件的transform,那么請(qǐng)不要使用這個(gè)控件的frame計(jì)算 子控件 的布局,應(yīng)該使用bounds+center代替。

  1. CAAnimation核心動(dòng)畫
    CAAnimation——所有動(dòng)畫對(duì)象的父類

3.1 設(shè)置動(dòng)畫的一種語法形式
addAnimation

/**

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

    [_demoView.layer addAnimation:anima forKey:@"shakeAnimation"];
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    3.2 CAAnimation繼承結(jié)構(gòu)
    CAAnimation{
    CAPropertyAnimation{
    CABasicAnimation{
    CASpringAnimation
    }
    CAKeyframeAnimation
    }
    CATransition
    CAAnimationGroup
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    是所有動(dòng)畫對(duì)象的父類,負(fù)責(zé)控制動(dòng)畫的持續(xù)時(shí)間和速度,是個(gè)抽象類,不能直接使用,應(yīng)該使用它具體的子類

3.3 CAAnimation類的屬性
帶*號(hào)代表來自CAMediaTiming協(xié)議的屬性)

*duration:動(dòng)畫的持續(xù)時(shí)間
*repeatCount:重復(fù)次數(shù),無限循環(huán)可以設(shè)置HUGE_VALF或者M(jìn)AXFLOAT
*repeatDuration:重復(fù)時(shí)間
removedOnCompletion:默認(rèn)為YES,代表動(dòng)畫執(zhí)行完畢后就從圖層上移除,圖形會(huì)恢復(fù)到動(dòng)畫執(zhí)行前的狀態(tài)。如果想讓圖層保持顯示動(dòng)畫執(zhí)行后的狀態(tài),那就設(shè)置為NO,不過還要設(shè)置fillMode為kCAFillModeForwards
*fillMode:決定當(dāng)前對(duì)象在非active時(shí)間段的行為。比如動(dòng)畫開始之前或者動(dòng)畫結(jié)束之后
*beginTime:可以用來設(shè)置動(dòng)畫延遲執(zhí)行時(shí)間,若想延遲2s,就設(shè)置為
CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當(dāng)前時(shí)間
timingFunction:速度控制函數(shù),控制動(dòng)畫運(yùn)行的節(jié)奏
delegate:動(dòng)畫代理
3.4 幾個(gè)重要屬性值
removedOnCompletion屬性值
CAAnimation——?jiǎng)赢嬏畛淠J?/p>

默認(rèn)為YES,代表動(dòng)畫執(zhí)行完畢后就從圖層上移除,圖形會(huì)恢復(fù)到動(dòng)畫執(zhí)行前的狀態(tài)。如果想讓圖層保持顯示動(dòng)畫執(zhí)行后的狀態(tài),那就設(shè)置為NO,不過還要設(shè)置fillMode為kCAFillModeForwards

fillMode屬性值
CAAnimation——控制恢復(fù)到動(dòng)畫執(zhí)行前

要想fillMode有效,最好設(shè)置removedOnCompletion = NO

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
在動(dòng)畫開始前,只需要將動(dòng)畫加入了一個(gè)layer,layer便立即進(jìn)入動(dòng)畫的初始狀態(tài)并等待動(dòng)畫開始。
kCAFillModeBoth
這個(gè)其實(shí)就是上面兩個(gè)的合成.動(dòng)畫加入后開始之前,layer便處于動(dòng)畫初始狀態(tài),動(dòng)畫結(jié)束后layer保持動(dòng)畫最后的狀態(tài)
如果 fillMode = kCAFillModeForwards 同時(shí) removedOnComletion = NO ,那么在動(dòng)畫執(zhí)行完畢后,圖層會(huì)保持顯示動(dòng)畫執(zhí)行后的狀態(tài)。但在實(shí)質(zhì)上,圖層的屬性值還是動(dòng)畫執(zhí)行前的初始值,并沒有真正被改變。

timingFunction屬性值
CAAnimation——?jiǎng)赢嬎俣瓤刂坪瘮?shù)

kCAMediaTimingFunctionLinear(線性):勻速,給你一個(gè)相對(duì)靜態(tài)的感覺
kCAMediaTimingFunctionEaseIn(漸進(jìn)):動(dòng)畫緩慢進(jìn)入,然后加速離開
kCAMediaTimingFunctionEaseOut(漸出):動(dòng)畫全速進(jìn)入,然后減速的到達(dá)目的地
kCAMediaTimingFunctionEaseInEaseOut(漸進(jìn)漸出):動(dòng)畫緩慢的進(jìn)入,中間加速,然后減速的到達(dá)目的地。這個(gè)是默認(rèn)的動(dòng)畫行為。

  1. CABasicAnimation
    基本動(dòng)畫,是CAPropertyAnimation的子類

4.1 特別屬性說明:
keyPath: 要改變的屬性名稱(傳字符串)
fromValue: keyPath相應(yīng)屬性的初始值
toValue: keyPath相應(yīng)屬性的結(jié)束值
4.2 keyPath可以是哪些值
CATransform3D{
//rotation旋轉(zhuǎn)
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
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
4.3 舉例
縮放動(dòng)畫 – transform.scale

//心臟縮放動(dòng)畫
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; //選中的這個(gè)keyPath就是縮放
scaleAnimation.fromValue = [NSNumber numberWithDouble:0.5]; //一開始時(shí)是0.5的大小
scaleAnimation.toValue = [NSNumber numberWithDouble:1.5]; //結(jié)束時(shí)是1.5的大小
scaleAnimation.duration = 1; //設(shè)置時(shí)間
scaleAnimation.repeatCount = MAXFLOAT; //重復(fù)次數(shù)
[_heartImageView.layer addAnimation:scaleAnimation forKey:@"CQScale"]; //添加動(dòng)畫
1
2
3
4
5
6
7
旋轉(zhuǎn)動(dòng)畫 – transform.rotation.z

//風(fēng)車旋轉(zhuǎn)動(dòng)畫
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"];
1
2
3
4
5
6
7
平移動(dòng)畫 – position.x/position.y

//平移動(dòng)畫
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"];
1
2
3
4
5
6
7

  1. CAKeyframeAnimation關(guān)鍵幀動(dòng)畫
    5.1 參數(shù)數(shù)組形式
    //根據(jù)values移動(dòng)的動(dòng)畫
    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];
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    5.2 path形式
    //指定path
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 200, 200, 200)];
    //指定path的動(dòng)畫
    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];
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  2. 組動(dòng)畫
    6.1 組動(dòng)畫
    上面單一動(dòng)畫的情況在實(shí)際開發(fā)中實(shí)際比較少,更多的時(shí)候是組合這些動(dòng)畫:創(chuàng)建不同類型的動(dòng)畫對(duì)象,設(shè)置好它們的參數(shù),然后把這些動(dòng)畫對(duì)象存進(jìn)數(shù)組,傳進(jìn)組動(dòng)畫對(duì)象的animations屬性中去。

6.2 示例
//創(chuàng)建組動(dòng)畫
CAAnimationGroup animationGroup = [CAAnimationGroup animation];
animationGroup.duration = 3;
animationGroup.repeatCount = MAXFLOAT;
animationGroup.removedOnCompletion = NO;
/
beginTime 可以分別設(shè)置每個(gè)動(dòng)畫的beginTime來控制組動(dòng)畫中每個(gè)動(dòng)畫的觸發(fā)時(shí)間,時(shí)間不能夠超過動(dòng)畫的時(shí)間,默認(rèn)都為0.f */

//縮放動(dòng)畫
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;

//按照?qǐng)A弧移動(dòng)動(dòng)畫
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;

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

  1. 貝塞爾曲線
    前面關(guān)鍵幀動(dòng)畫章節(jié)提到了貝塞爾曲線,這個(gè)曲線很有用,在iOS開發(fā)中有兩種形式可用:CGMutablePathRef和UIBezierPath,均可以通過制定控制點(diǎn)數(shù)組的形式唯一確定曲線,也可以通過矩形內(nèi)切橢圓唯一確定曲線。下面是兩者的例子:

7.1 CGMutablePathRef
通過 關(guān)鍵點(diǎn)曲線連接 唯一確定

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

// 設(shè)置其他屬性
keyframeAnimation.duration = 4;
keyframeAnimation.beginTime = CACurrentMediaTime() + 1; // 設(shè)置延遲2秒執(zhí)行, 不設(shè)置這個(gè)屬性, 默認(rèn)直接執(zhí)行
// 3. 添加動(dòng)畫到圖層, 會(huì)自動(dòng)執(zhí)行
[_layer addAnimation:keyframeAnimation forKey:@"GGKeyframeAnimation"];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.2 UIBezierPath
通過 矩形內(nèi)切橢圓 唯一確定

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"];
1
2
3
4
5
通過 關(guān)鍵點(diǎn)直線連接 唯一確定

-(void)pathAnimation2{

//創(chuàng)建path
UIBezierPath *path = [UIBezierPath bezierPath];
//設(shè)置線寬
path.lineWidth = 3;
//線條拐角
path.lineCapStyle = kCGLineCapRound;
//終點(diǎn)處理
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"];

}

作者:H.A.N
來源:CSDN
原文:https://blog.csdn.net/u010960265/article/details/80930068
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請(qǐng)附上博文鏈接!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容