移動開發(IOS) – 動畫
1.CALayer
1.1.學習核心動畫之前,需要先理解 CALayer,因爲核心動畫操作的對象不是 UIView,而是 CALayer 。
1.2.CALayer 是核心動畫的基礎,可以做圓角、陰影、邊框等效果 。
1.3.每個 UIView 內部都有一個 Layer 的屬性 。
1.4.在實現核心動畫時,本質上是將 CALayer 中的內容轉換成位圖,從而便於圖形硬件的操縱 。
1.5.在 UIView 中 CALayer 只是一個類聲明,因此需要添加 QuartzCore 框架 。
1.6.UIKit 框架只能應用在 iOS 而不能用於 Mac,但是 Quartz 2D 是可以跨平臺的,因此在使用顏色時,不能直接使用 UIColor而需要將顏色轉成 CGColor 。
1.7.修改圖層相當於修改UIView屬性,即修改了界面屬性 。
1.8.形變屬性既可以用形變函數指定,也可以用keyPath指定 。
1.9.創建視圖對象時,視圖會自己創建一個層,視圖在繪圖(如 drawRect: )時,會將內容畫在自己的層上。當視圖在層上完成繪圖後,系統會將圖層拷貝至屏幕。每個視圖都有一個層,而每個圖層又可以有多個子層 。
1.10.Layer 的設計目的不是爲了取代視圖,因此不能基於 CALayer 創建一個獨立的可視化組件 。
1.11.Layer 的設計目的是提供視圖的基本可視內容,從而提高動畫的執行效率 。
1.12.除提供可視內容外,Layer 不負責視圖的事件響應、內容繪製等工作,同時 Layer 不能參與到響應者鏈條中 。
1.13.CALayer 層次結構:
1.14.CALayer 的使用說明
1.14.1.通過 UIView 的 layer 屬性可以拿到對應的根層,這個層不允許重新創建,但可以往層裏面添加子層(調用 CALayer 的 addSublayer )。
1.14.2.要具體使用CALayer,需要引入<QuartzCore/QuartzCore.h>。
1.14.3.獲取當前圖層或使用靜態方法 layer 初始化 CALayer 後,可以設置以下屬性:
bounds | 寬度和高度 |
position | 位置(默認指中心點,具體由 anchorPoint 決定) |
anchorPoint | 錨點( x,y 的範圍都是 0-1 ),決定了 position 的含義 |
backgroundColor | 背景顏色( CGColorRef 類型) |
borderColor | 邊框顏色( CGColorRef 類型) |
borderWidth | 邊框寬度 |
cornerRadius | 圓角半徑 |
contents | 內容(比如設置爲圖片 CGImageRef ) |
transform | 旋轉、縮放、平移 |
1.14.4.雖然 CALayer 可以使用 frame,但最好還是使用 bounds 和 position。爲層設置動畫時,用 bounds 和 position 會方便一點。
1.14.5.注意錨點和位置的關係,以及在旋轉轉換時對圖層的影響。
1.14.6.UIView 有一個 addSubview 方法,而 layer 有一個 addSubLayer 方法。
1.14.7.CALayer 中使用 CGColorRef 和 CGImageRef 的數據類型,而不用 UIColor 和 UIImage 。
1.14.8.可以通過 UIKi t對象的特定方法,可以得到 Core Graphics 對象,如 UIImage 的 CGImage 方法和 UIColor 的 CGColor 方法。
1.15.CALayer 的隱式動畫屬性
1.15.1.每一個 UIView 內部都默認關聯着一個 CALayer,稱這個 Layer 爲 Root Layer。所有的非 Root Layer 都存在着隱式動畫,隱式動畫的默認時長爲 1/4 秒。
1.15.2.當修改非 Root Layer 的部分屬性時,相應的修改會自動產生動畫效果,能執行隱式動畫的屬性被稱爲“可動畫屬性”,諸如:
bounds | 縮放動畫 |
position | 平移動畫 |
opacity | 淡入淡出動畫(改變透明度) |
… … | … … |
1.15.3.如果要關閉默認的動畫效果,可以通過動畫事務方法實現:
1
2
3
4
|
[CATransaction begin]; [CATransaction setDisableActions: YES ]; // ... [CATransaction commit]; |
1.16.在 CALayer 上繪圖
1.16.1.創建一個 CALayer 的子類,然後覆蓋 drawInContext: 方法,可以使用 Quartz2D API 在其中進行繪圖。
1.16.2.設置 CALayer 的 delegate,然後讓 delegate 實現 drawLayer:inContext: 方法進行繪圖。
1.16.3.不能再將 UIView 設置爲這個 CALayer 的 delegate,因爲 UIView 對象已經是內部層的 delegate,再次設置會出問題。
1.16.4.無論使用哪種方法,都必須向層發送 setNeedsDisplay 消息,以觸發相應繪圖方法的調用。
1.17.CALayer、 UIView 以及上下文之間的關係:
1.17.1.當 UIView 收到 setNeedsDisplay 消息時,CALayer 會準備好一個 CGContextRef,然後向它的 delegate 即 UIView,發送消息,並且傳入已經準備好的 CGContextRef 對象。UIView 在 drawLayer:inContext: 方法中會調用自己的 drawRect: 方法。
1.17.2.平時在 drawRect: 中通過 UIGraphicsGetCurrentContext() 獲取的就是由 CALayer 傳入的 CGContextRef 對象,在 drawRect: 中完成的所有繪圖都會填入 CALayer 的 CGContextRef 中,然後被拷貝至屏幕。
1.17.3. CALayer 的 CGContextRef 用的是位圖上下文( Bitmap Graphics Context )。
1.18.在實現核心動畫時,本質上是將 CALayer 中的內容轉換成位圖,從而便於圖形硬件的操縱。
2.Core Animation
2.1.Core Animation 是跨平臺的,支持 iOS 環境和 Mac OS X 環境。
2.2.使用它需要先添加 QuartzCore.framework 和引入對應的框架 <QuartzCore/QuartzCore.h> 。
2.3.開發步驟:
2.3.1.初始化一個動畫對象 ( CAAnimation ) 並設置一些動畫相關屬性。
2.3.2.CALayer 中很多屬性都可以通過 CAAnimation 實現動畫效果,包括:opacity、 position、 transform、 bounds、 contents 等( 可以在 API 文檔中搜索: CALayer Animatable Properties )。
2.3.3.添加動畫對象到層( CALayer )中,開始執行動畫。
2.3.4.通過調用 CALayer 的 addAnimation:forKey 增加動畫到層( CALayer )中,這樣就能觸發動畫了。通過調用 removeAnimationForKey 可以停止層中的動畫。
2.3.5.Core Animation 的動畫執行過程都是在後臺操作的,不會阻塞主線程。
3.CAAnimation
3.1.CAAnimation 繼承結構
3.2.CAAnimation 是所有動畫對象的父類,負責控制動畫的持續時間和速度,是個抽象類,不能直接使用,應該使用它具體的子類。
3.3.屬性說明:
duration | (來自CAMediaTiming協議的屬性)動畫的持續時間 |
repeatCount | (來自CAMediaTiming協議的屬性)重複次數,無限循環可以設置 HUGE_VALF 或者 MAXFLOAT |
repeatDuration | (來自CAMediaTiming協議的屬性)重複時間 |
removedOnCompletion | 默認爲 YES,代表動畫執行完畢後就從圖層上移除,圖形會恢復到動畫執行前的狀態。如果想讓圖層保持顯示動畫執行後的狀態,那就設置爲 NO,不過還要設置 fillMode 爲 kCAFillModeForwards |
fillMode | (來自CAMediaTiming協議的屬性)決定當前對象在非active時間段的行爲。比如動畫開始之前或者動畫結束之後 |
beginTime | (來自CAMediaTiming協議的屬性)可以用來設置動畫延遲執行時間,若想延遲 2s,就設置爲 CACurrentMediaTime()+2 , CACurrentMediaTime() 爲圖層的當前時間 |
timingFunction | 速度控制函數,控制動畫運行的節奏 |
delegate | 動畫代理 |
3.4.CAAnimation 的動畫填充模式,fillMode 屬性值(要想 fillMode 有效,最好設置 removedOnCompletion = NO ):
3.4.1.kCAFillModeRemoved 這個是默認值,也就是說當動畫開始前和動畫結束後,動畫對 layer 都沒有影響,動畫結束後,layer 會恢復到之前的狀態。
3.4.2.kCAFillModeForwards 當動畫結束後,layer 會一直保持着動畫最後的狀態 。
3.4.3.kCAFillModeBackwards 在動畫開始前,只需要將動畫加入了一個 layer,layer 便立即進入動畫的初始狀態並等待動畫開始。
3.4.4.kCAFillModeBoth 這個其實就是上面兩個的合成.動畫加入後開始之前,layer 便處於動畫初始狀態,動畫結束後 layer 保持動畫最後的狀態。
3.5.CAAnimation 的速度控制函數( CAMediaTimingFunction ):
3.5.1. kCAMediaTimingFunctionLinear (線性):勻速,給你一個相對靜態的感覺。
3.5.2. kCAMediaTimingFunctionEaseIn (漸進):動畫緩慢進入,然後加速離開。
3.5.3. kCAMediaTimingFunctionEaseOut (漸出):動畫全速進入,然後減速的到達目的地。
3.5.4. kCAMediaTimingFunctionEaseInEaseOut (漸進漸出):動畫緩慢的進入,中間加速,然後減速的到達目的地。這個是默認的動畫行爲。
3.6.CAAnimation 動畫代理方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@interface
NSObject
(CAAnimationDelegate) /* Called when the animation begins its active duration. */ - ( void )animationDidStart:(CAAnimation *)anim; /* Called when the animation either completes its active duration or * is removed from the object it is attached to (i.e. the layer). 'flag' * is true if the animation reached the end of its active duration * without being removed. */ - ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag; @end |
3.7.CALayer上動畫的暫停和恢復:
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
|
#pragma mark 暫停CALayer的動畫 -( void )pauseLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer: nil ]; // 讓CALayer的時間停止走動 layer.speed = 0.0; // 讓CALayer的時間停留在pausedTime這個時刻 layer.timeOffset = pausedTime; } #pragma mark 恢復CALayer的動畫 -( void )resumeLayer:(CALayer*)layer { CFTimeInterval pausedTime = layer.timeOffset; // 1. 讓CALayer的時間繼續行走 layer.speed = 1.0; // 2. 取消上次記錄的停留時刻 layer.timeOffset = 0.0; // 3. 取消上次設置的時間 layer.beginTime = 0.0; // 4. 計算暫停的時間(這裏也可以用CACurrentMediaTime()-pausedTime) CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer: nil ]
- pausedTime; // 5. 設置相對於父座標系的開始時間(往後退timeSincePause) layer.beginTime = timeSincePause; } |
4.CAPropertyAnimation
4.1.CAPropertyAnimation 是 CAAnimation 的子類,也是個抽象類,要想創建動畫對象,應該使用它的兩個子類: CABasicAnimation, CAKeyframeAnimation 。
4.2.屬性說明:
keyPath | 通過指定 CALayer 的一個屬性名稱爲 keyPath ( NSString 類型),並且對 CALayer 的這個屬性的值進行修改,達到相應的動畫效果。比如,指定 @”position” 爲 keyPath,就修改 CALayer 的 position 屬性的值,以達到平移的動畫效果。 |
5.CABasicAnimation
5.1.基本 CABasicAnimation,是 CAPropertyAnimation 的子類。
5.2.屬性說明:
fromValue | keyPath 相應屬性的初始值 |
toValue | keyPath 相應屬性的結束值 |
5.3.動畫過程說明:
5.3.1.隨着動畫的進行,在長度爲 duration 的持續時間內,keyPath 相應屬性的值從 fromValue 漸漸地變爲 toValue 。
5.3.2.keyPath 內容是 CALayer 的可動畫 Animatable 屬性。
5.3.3.如果 fillMode = kCAFillModeForwards 同時 removedOnComletion = NO ,那麼在動畫執行完畢後,圖層會保持顯示動畫執行後的狀態。但在實質上,圖層的屬性值還是動畫執行前的初始值,並沒有真正被改變 。
5.3.4.如果只是實現簡單屬性變化的動畫效果,可以使用 UIView 的 block 動畫替代基本動畫。
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
|
/***平移***/ // 1. 實例化動畫 // 如果沒有指定圖層的錨點(定位點)postion對應UIView的中心點 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: @"position" ]; // 2. 設置動畫屬性 // 1) fromValue(myView的當前座標) & toValue [anim setToValue:[ NSValue
valueWithCGPoint:point]]; // 2) 動畫的時長 [anim setDuration:1.0f]; // 3) 設置代理 [anim setDelegate: self ]; // 4) 讓動畫停留在目標位置 /* *提示:通過設置動畫在完成後不刪除,以及向前填充,可以做到平移動畫結束後, *UIView看起來停留在目標位置,但是其本身的frame並不會發生變化 */ [anim setRemovedOnCompletion: NO ]; // forwards是逐漸逼近目標點 [anim setFillMode:kCAFillModeForwards]; // 5) 要修正座標點的實際位置可以利用setValue方法 [anim setValue:[ NSValue
valueWithCGPoint:point] forKey: @"targetPoint" ]; [anim setValue: @"translationTo"
forKey: @"animationType" ]; // 3. 將動畫添加到圖層 // 將動畫添加到圖層之後,系統會按照定義好的屬性開始動畫,通常程序員不在與動畫進行交互 [ self .myView.layer addAnimation:anim forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/***代理方法***/ //動畫開始(極少用) - ( void )animationDidStart:(CAAnimation *)anim { NSLog ( @"開始動畫" ); } //動畫結束(通常在動畫結束後,做動畫的後續處理) - ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag { NSString
*type = [anim valueForKey: @"animationType" ]; if
([type isEqualToString: @"translationTo" ]) { // 1. 通過鍵值取出需要移動到的目標點 CGPoint point = [[anim valueForKey: @"targetPoint" ]CGPointValue]; NSLog ( @"目標點: %@" ,
NSStringFromCGPoint (point)); // 2. 設置myView的座標點 [ self .myView setCenter:point]; } NSLog ( @"結束動畫,myView: %@" ,
NSStringFromCGRect ( self .myView.frame)); } |
1
2
3
4
5
6
|
/***block 動畫***/ [UIView animateWithDuration:1.0f animations:^{ [ self .myView setCenter:location]; } completion:^( BOOL
finished) { NSLog ( @"%@" ,
NSStringFromCGRect ( self .myView.frame)); }]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/***旋轉動畫***/ // 1. 實例化基本動畫 // 默認按照z軸旋轉 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: @"transform.rotation.z" ]; [ self .myView.layer setAnchorPoint:CGPointMake(0, 0)]; // 2. 設置動畫屬性 // 不停的旋轉 // 1) 旋轉一週 [anim setToValue:@(2 * M_PI)]; // 2) 不停的旋轉 - 動畫循環播放 // HUGE_VALF 是一個非常大得浮點數,指定此數值可以認爲動畫無限循環,這裏不要使用 MAXFLOAT [anim setRepeatCount:HUGE_VALF]; [anim setDuration:0.5f]; // 3) 動畫完成時刪除 // 對於循環播放的動畫效果,一定要將 removedOnCompletion 設置爲 NO,否則無法恢復動畫 [anim setRemovedOnCompletion: NO ]; // 3. 添加動畫 // key 可以隨便指定,用於判斷圖層中是否存在該動畫 [ self .myView.layer addAnimation:anim forKey: @"rotationAnim" ]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/***縮放動畫***/ // 1. 實例化基本動畫 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: @"transform.scale" ]; // 2. 設置動畫屬性 // fromValue & toValue [anim setFromValue:@(1.0)]; // 從當前大小縮小到一半,然後恢復初始大小 [anim setToValue:@(0.5)]; // 自動翻轉動畫 [anim setAutoreverses: YES ]; // 動畫時長 [anim setDuration:0.5f]; // 3. 將動畫添加到圖層 [ self .myView.layer addAnimation:anim forKey: nil ]; |
6.CAKeyframeAnimation
6.1.CAKeyframeAnimation ,也是 CAPropertyAnimation 的子類。
6.2.與 CABasicAnimation 的區別是:
6.2.1.CABasicAnimation 只能從一個數值( fromValue )變到另一個數值( toValue ),而 CAKeyframeAnimation 會使用一個 NSArray 保存這些數值 。
6.2.2.CABasicAnimation 可看做是隻有2個關鍵幀的 CAKeyframeAnimation 。
6.3.常用屬性:
values | 上述的NSArray對象。裏面的元素稱爲”關鍵幀” ( keyframe )。動畫對象會在指定的時間( duration )內,依次顯示 values 數組中的每一個關鍵幀。 |
path | 可以設置一個 CGPathRef、 CGMutablePathRef ,讓圖層按照路徑軌跡移動。path 只對 CALayer 的 anchorPoint 和position 起作用。如果設置了 path,那麼 values 將被忽略。 |
keyTimes | 可以爲對應的關鍵幀指定對應的時間點,其取值範圍爲0到1.0,keyTimes 中的每一個時間值都對應values中的每一幀。如果沒有設置 keyTimes ,各個關鍵幀的時間是平分的。 |
1
2
3
4
5
6
7
8
9
10
11
|
/***晃動動畫***/ //實例化關鍵幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"transform.rotation" ]; [anim setDuration:0.5f]; //晃動角度 CGFloat angel = M_PI_4 / 12.0; [anim setValues:@[@(angel), @(-angel), @(angel)]]; //設置循環晃動 [anim setRepeatCount:HUGE_VALF]; //將動畫添加到圖層 [ self .layer addAnimation:anim forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/***離散點平移動畫***/ // 1. 實例化關鍵幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ]; // 2. 設置關鍵幀動畫屬性 NSValue
*p1 = [ NSValue
valueWithCGPoint: self .center]; NSValue
*p2 = [ NSValue
valueWithCGPoint:CGPointMake(0, 0)]; NSValue
*p3 = [ NSValue
valueWithCGPoint:point]; [anim setValues:@[p1, p2, p3]]; [anim setDuration:1.0f]; //設置鍵值記錄目標位置,以便動畫結束後,修正位置 [anim setValue: @"translationTo"
forKey: @"animationType" ]; [anim setValue:p3 forKey: @"targetPoint" ]; //設置代理 [anim setDelegate: self ]; // 3. 將動畫添加到圖層 [ self .layer addAnimation:anim forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/***路徑平移動畫***/ // 1. 實例化關鍵幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ]; [anim setDuration:duration]; // 2. 按照矩形移動,需要使用到路徑 // 1) 創建路徑 CGMutablePathRef path = CGPathCreateMutable(); // 2) 設置路徑內容 // 起點,寬、高 CGFloat w = to.x -
self .center.x; CGFloat h = to.y -
self .center.y; CGRect rect = CGRectMake( self .center.x,
self .center.y, w, h); CGPathAddRect(path,
nil , rect); // 3) 將路徑添加到動畫 [anim setPath:path]; // 4) 釋放路徑 CGPathRelease(path); // 3. 將動畫添加到圖層 [ self .layer addAnimation:anim forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/***貝塞爾曲線(一個控制點)動畫***/ // 1. 實例化關鍵幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ]; [anim setDuration:duration]; // 2. 設置路徑 // 中間的控制點使用屏幕上得隨機點 CGPoint cp = [ self
randomPoint]; CGMutablePathRef path = CGPathCreateMutable(); // 設置起始點 CGPathMoveToPoint(path,
NULL ,
self .center.x,
self .center.y); // 添加帶一個控制點的貝塞爾曲線 CGPathAddQuadCurveToPoint(path,
NULL , cp.x, cp.y, to.x, to.y); [anim setPath:path]; CGPathRelease(path); // 設置鍵值記錄目標位置,以便動畫結束後,修正位置 [anim setValue: @"translationTo"
forKey: @"animationType" ]; [anim setValue:[ NSValue
valueWithCGPoint:to] forKey: @"targetPoint" ]; [anim setDelegate: self ]; // 3. 將動畫添加到圖層 [ self .layer addAnimation:anim forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/***貝塞爾曲線(兩個控制點)動畫***/ // 1. 實例化關鍵幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ]; // 2. 設置路徑 [anim setDuration:duration]; // 中間的控制點使用屏幕上得隨機點 CGPoint cp1 = [ self
randomPoint]; CGPoint cp2 = [ self
randomPoint]; CGMutablePathRef path = CGPathCreateMutable(); // 設置起始點 CGPathMoveToPoint(path,
NULL ,
self .center.x,
self .center.y); // 添加帶一個控制點的貝塞爾曲線 CGPathAddCurveToPoint(path,
NULL , cp1.x, cp1.y, cp2.x, cp2.y, to.x, to.y); [anim setPath:path]; CGPathRelease(path); // 設置鍵值記錄目標位置,以便動畫結束後,修正位置 [anim setValue: @"translationTo"
forKey: @"animationType" ]; [anim setValue:[ NSValue
valueWithCGPoint:to] forKey: @"targetPoint" ]; [anim setDelegate: self ]; // 3. 將動畫添加到圖層 [ self .layer addAnimation:anim forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
|
/***動畫代理方法***/ - ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag { // 取出動畫類型 NSString
*type = [anim valueForKey: @"animationType" ]; if
([type isEqualToString: @"translationTo" ]) { // 取出目標點,並設置self.center self .center = [[anim valueForKey: @"targetPoint" ]CGPointValue]; } } |
6.4.CAKeyframeAnimation 計算模式屬性 (calculationMode)
6.4.1.所謂計算模式:其主要針對的是每一幀的內容爲一個座標點的情況,也就是對 anchorPoint 和 position 進行的動畫。
6.4.2.當在平面座標系中有多個離散的點的時候,可以是離散的,也可以直線相連後進行插值計算,也可以使用圓滑的曲線將他們相連後進行插值計算。
6.4.3.calculationMode目前提供如下幾種模式:
kCAAnimationLinear | 默認值,表示當關鍵幀爲座標點的時候,關鍵幀之間直接直線相連進行插值計算 |
kCAAnimationDiscrete | 離散的,不進行插值計算,所有關鍵幀直接逐個進行顯示 |
kCAAnimationPaced | 使得動畫均勻進行,而不是按 keyTimes 設置的或者按關鍵幀平分時間,此時 keyTimes 和 timingFunctions 無效 |
kCAAnimationCubic | 對關鍵幀爲座標點的關鍵幀進行圓滑曲線相連後插值計算,這裏的主要目的是使得運行的軌跡變得圓滑 |
kCAAnimationCubicPaced | 在 kCAAnimationCubic 的基礎上使得動畫運行變得均勻,就是系統時間內運動的距離相同,此時 keyTimes 以及 timingFunctions 也是無效的。 |
6.4.4.此屬性研究的優先級不高,只有再做複雜動畫,同時動畫效果不理想的時候,才需要考慮使用這一屬性。
7.CAAnimationGroup
7.1.CAAnimationGroup,是CAAnimation的子類,可以保存一組動畫對象,將CAAnimationGroup對象加入層後,組中所有動畫對象可以同時併發運行。
7.2.屬性說明:
animations | 用來保存一組動畫對象的 NSArray |
7.3.默認情況下,一組動畫對象是同時運行的,也可以通過設置動畫對象的 beginTime 屬性來更改動畫的開始時間。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/***動畫組***/ // 1. 實例化動畫組 CAAnimationGroup *group = [[CAAnimationGroup alloc]init]; CFTimeInterval duration = 2.0; // 2. 定義動畫組中的動畫 CAKeyframeAnimation *move = [AnimationView moveWithDuration:duration from: self .myView.center
to:location controlPointCount:4]; CABasicAnimation *rotation = [AnimationView rotationWithDuration:duration from:0.0 to:2 * M_PI]; CABasicAnimation *scale = [AnimationView scaleWithDuration:duration from:2.0 to:0.5]; CABasicAnimation *opacity = [AnimationView opacityWithDuration:duration from:0.1 to:1.0]; // 3. 將定義的動畫添加到動畫組 [group setAnimations:@[move, rotation, scale, opacity]]; // 定義動畫組執行的時間長度 [group setDuration:duration]; // 5) 設置鍵值記錄目標位置,以便動畫結束後,修正位置 // 並不是所有的動畫方法都需要設置目標點 [group setValue: @"translationTo"
forKey: @"animationType" ]; [group setValue:[ NSValue
valueWithCGPoint:location] forKey: @"targetPoint" ]; [group setDelegate: self ]; // 4. 將動畫組添加到視圖的圖層 [ self .myView.layer addAnimation:group forKey: nil ]; |
1
2
3
4
5
6
7
8
9
10
|
/***動畫代理方法***/ - ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag { // 取出動畫類型 NSString
*type = [anim valueForKey: @"animationType" ]; if
([type isEqualToString: @"translationTo" ]) { // 取出目標點,並設置self.center self .center = [[anim valueForKey: @"targetPoint" ]CGPointValue]; } } |
8.CATransition
8.1.CATransition 是 CAAnimation 的子類,用於做轉場動畫,能夠爲層提供移出屏幕和移入屏幕的動畫效果。 iOS 比 Mac OS X 的轉場動畫效果少一點。
8.2.UINavigationController 就是通過 CATransition 實現了將控制器的視圖推入屏幕的動畫效果。
8.3.動畫屬性:
type | 動畫過渡類型 |
subtype | 動畫過渡方向 |
startProgress | 動畫起點(在整體動畫的百分比) |
endProgress | 動畫終點(在整體動畫的百分比) |
8.4.轉場動畫過渡效果:
類型字符串 | 效果說明 | 關鍵字 | 方向 |
fade | 交叉淡化過渡 | YES | |
push | 新視圖把舊視圖推出去 | YES | |
moveIn | 新視圖移到舊視圖上面 | YES | |
reveal | 將舊視圖移開,顯示下面的新視圖 | YES | |
cube | 立方體翻滾效果 | ||
oglFlip | 上下左右翻轉效果 | ||
suckEffect | 收縮效果,如一塊布被抽走 | NO | |
rippleEffect | 水滴效果 | NO | |
pageCurl | 向上翻頁效果 | ||
pageUnCurl | 向下翻頁效果 | ||
cameraIrisHollowOpen | 相機鏡頭打開效果 | NO | |
cameraIrisHollowClose | 相機鏡頭關閉效果 | NO |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 1. 實例化轉場動畫 注意不要和CATransaction(動畫事務)搞混 CATransition *transition = [[CATransition alloc]init]; // 設置類型 type [transition setType: @"moveIn" ]; // 根據輕掃方向設置子類型 subType // 2. 判斷輕掃的方向 UIImageView *imageView = (UIImageView *)recognizer.view; if
(UISwipeGestureRecognizerDirectionLeft == recognizer.direction) { NSLog ( @"向左" ); [transition setSubtype:kCATransitionFromRight]; imageView.tag = (imageView.tag + 1) %
self .imageList.count; }
else
{ NSLog ( @"向右" ); [transition setSubtype:kCATransitionFromLeft]; // 針對負數去模,需要注意修正索引 imageView.tag = (imageView.tag - 1 +
self .imageList.count) %
self .imageList.count; } [transition setDuration:0.5f]; [imageView setImage: self .imageList[imageView.tag]]; // 3. 動畫添加到圖層 [recognizer.view.layer addAnimation:transition forKey: nil ]; |
8.5.使用UIView動畫函數實現轉場動畫(單視圖):
1
2
3
4
5
6
7
8
|
/* * duration:動畫的持續時間 * view:需要進行轉場動畫的視圖 * options:轉場動畫的類型 * animations:將改變視圖屬性的代碼放在這個block中 * completion:動畫結束後,會自動調用這個block */ + ( void )transitionWithView:(UIView *)view duration:( NSTimeInterval )duration
options:(UIViewAnimationOptions)options animations:( void
(^)( void ))animations completion:( void
(^)( BOOL
finished))completion; |
1
2
3
4
5
6
7
8
|
/***單視圖(翻轉轉場動畫)***/ [UIView transitionWithView: self .imageView duration:1.0f options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ // 在此設置視圖反轉之後顯示的內容 self .imageView.tag = ( self .imageView.tag
+ 1) % self .imageList.count; [ self .imageView setImage: self .imageList[ self .imageView.tag]]; } completion:^( BOOL
finished) { NSLog ( @"翻轉完成" ); }]; |
8.6.使用 UIView 動畫函數實現轉場動畫(雙視圖):
1
2
3
4
5
6
7
|
/* * duration:動畫的持續時間 * options:轉場動畫的類型 * animations:將改變視圖屬性的代碼放在這個block中 * completion:動畫結束後,會自動調用這個block */ + ( void )transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:( NSTimeInterval )duration
options:(UIViewAnimationOptions)options completion:( void
(^)( BOOL
finished))completion; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/***雙視圖***/ // 在雙視圖轉場時,我們可以根據是否有父視圖,來判斷誰進誰出 UIView *fromView =
nil ; UIView *toView =
nil ; if
( self .subView1.superview ==
nil ) { // 說明subView1要轉入 toView =
self .subView1; fromView =
self .subView2; }
else
{ // 說明subView2要轉入 toView =
self .subView2; fromView =
self .subView1; } [UIView transitionFromView:fromView toView:toView duration:1.0f options:UIViewAnimationOptionTransitionFlipFromTop completion:^( BOOL
finished) { NSLog ( @"轉場完成" ); // 每次轉場後,會調整參與轉場視圖的父視圖,因此,參與轉場視圖的屬性,需要是強引用 // 轉場之後,入場的視圖會有兩個強引用,一個是視圖控制器,另一個是視圖 NSLog ( @"subView1's superView: %@" ,
self .subView1.superview); NSLog ( @"subView2's superView: %@" ,
self .subView2.superview); }]; |
8.6.1.使用雙視圖轉場動畫時,需要掌握視圖的 superView 屬性的變化。
8.6.2.方法調用完畢後,相當於執行了下面兩句代碼:
1
2
3
4
|
// 添加toView到父視圖 [fromView.superview addSubview:toView]; // 把fromView從父視圖中移除 [fromView.superview removeFromSuperview]; |
8.7.轉場動畫存在的問題是動畫過程中無法交互,如果要在切換時實現交互效果需要使用 UIScrollView + UIPageControl 。
9.UIActivityIndicatorView
9.1.UIActivityIndicatorView 是一個旋轉進度輪,可以用來告知用戶有一個操作正在進行中,一般用initWithActivityIndicatorStyle 初始化。
9.2.相關方法:
- (void)startAnimating; | 開始動畫 |
- (void)stopAnimating; | 停止動畫 |
- (BOOL)isAnimating; | 是否正在運行動畫 |
9.3.屬性數值:
UIActivityIndicatorViewStyleWhiteLarge | 大型白色指示器 |
UIActivityIndicatorViewStyleWhite | 標準尺寸白色指示器 |
UIActivityIndicatorViewStyleGray | 灰色指示器,用於白色背景 |
9.3.常用第三方框架 SVProgressHUB
9.3.1.常用顯示方法:showWithStatus ; showWithStatus:maskType:
9.3.2.關閉方法:dismiss
9.3.3.SVProgressHUB 對 UIActivityIndicatorView 進行了封裝,增加了文字、圖像以及容器視圖等屬性,通過類方法調用,使用簡單。
9.3.4.使用 SVProgressHUDMaskTypeGradient 等屬性顯示提示信息時,可以使用 NSTimer 模擬等待後臺響應效果。
10.UIImageView 的序列幀動畫
10.1.UIImageView可以讓一系列的圖片在特定的時間內按順序顯示。
10.2.屬性說明:
animationImages | 要顯示的一組圖片序列 |
animationDuration | 完整地顯示所有圖片所需的時間 |
animationRepeatCount | 動畫的執行次數(默認爲0,代表無限循環) |
10.3.相關方法:
- (void)startAnimating; | 開始動畫 |
- (void)stopAnimating; | 停止動畫 |
- (BOOL)isAnimating; | 是否正在運行動畫 |
11.CADisplayLink
11.1.CADisplayLink 是一種以屏幕刷新頻率觸發的時鐘機制,每秒鐘執行大約60次左右。
11.2.CADisplayLink 是一個計時器,可以使繪圖代碼與視圖的刷新頻率保持同步,而 NSTimer 無法確保計時器實際被觸發的準確時間。
11.3.使用方法:
11.3.1.定義 CADisplayLink 並制定觸發調用方法
11.3.2.將顯示鏈接添加到主運行循環隊列
1
2
3
4
5
|
// 實例化遊戲時鐘 // 1. 實例化遊戲時鐘,並添加監聽方法 self .gameTimer = [CADisplayLink displayLinkWithTarget: self
selector: @selector (step)]; // 2. 添加到主運行循環,否則監聽方法不會被觸發 [ self .gameTimer addToRunLoop:[ NSRunLoop
mainRunLoop] forMode: NSDefaultRunLoopMode ]; |