1. 程式人生 > >事務(隱式動畫)

事務(隱式動畫)

class with 所有 管理 () cal round animate 循環

事務

Core Animation基於一個假設,說屏幕上的任何東西都可以(或者可能)做動畫。動畫並不需要你在Core Animation中手動打開,相反需要明確地關閉,否則他會一直存在。

當你改變CALayer的一個可做動畫的屬性,它並不能立刻在屏幕上體現出來。相反,它是從先前的值平滑過渡到新的值。這一切都是默認的行為,你不需要做額外的操作。

這看起來這太棒了,似乎不太真實,我們來用一個demo解釋一下:首先和第一章“圖層樹”一樣創建一個藍色的方塊,然後添加一個按鈕,隨機改變它的顏色。代碼見清單7.1。點擊按鈕,你會發現圖層的顏色平滑過渡到一個新值,而不是跳變(圖7.1)。

清單7.1 隨機改變圖層顏色

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *layerView;
 4 @property (nonatomic, weak) IBOutlet CALayer *colorLayer;/*熱心人發現這裏應該改為@property (nonatomic, strong)  CALayer *colorLayer;否則運行結果不正確。
 5 */
 6 @end
 7 
 8 @implementation ViewController
 9 
10 - (void)viewDidLoad
11 { 12 [super viewDidLoad]; 13 //create sublayer 14 self.colorLayer = [CALayer layer]; 15 self.colorLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f); 16 self.colorLayer.backgroundColor = [UIColor blueColor].CGColor; 17 //add it to our view 18 [self.layerView.layer addSublayer:self.colorLayer];
19 } 20 21 - (IBAction)changeColor 22 { 23 //randomize the layer background color 24 CGFloat red = arc4random() / (CGFloat)INT_MAX; 25 CGFloat green = arc4random() / (CGFloat)INT_MAX; 26 CGFloat blue = arc4random() / (CGFloat)INT_MAX; 27 self.colorLayer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor; ? 28 } 29 30 @end

技術分享

圖7.1 添加一個按鈕來控制圖層顏色

這其實就是所謂的隱式動畫。之所以叫隱式是因為我們並沒有指定任何動畫的類型。我們僅僅改變了一個屬性,然後Core Animation來決定如何並且何時去做動畫。Core Animaiton同樣支持顯式動畫,下章詳細說明。

但當你改變一個屬性,Core Animation是如何判斷動畫類型和持續時間的呢?實際上動畫執行的時間取決於當前事務的設置,動畫類型取決於圖層行為

事務實際上是Core Animation用來包含一系列屬性動畫集合的機制,任何用指定事務去改變可以做動畫的圖層屬性都不會立刻發生變化,而是當事務一旦提交的時候開始用一個動畫過渡到新值。

事務是通過CATransaction類來做管理,這個類的設計有些奇怪,不像你從它的命名預期的那樣去管理一個簡單的事務,而是管理了一疊你不能訪問的事務。CATransaction沒有屬性或者實例方法,並且也不能用+alloc-init方法創建它。但是可以用+begin+commit分別來入棧或者出棧。

任何可以做動畫的圖層屬性都會被添加到棧頂的事務,你可以通過+setAnimationDuration:方法設置當前事務的動畫時間,或者通過+animationDuration方法來獲取值(默認0.25秒)。

Core Animation在每個run loop周期中自動開始一次新的事務(run loop是iOS負責收集用戶輸入,處理定時器或者網絡事件並且重新繪制屏幕的東西),即使你不顯式的用[CATransaction begin]開始一次事務,任何在一次run loop循環中屬性的改變都會被集中起來,然後做一次0.25秒的動畫。

明白這些之後,我們就可以輕松修改變色動畫的時間了。我們當然可以用當前事務的+setAnimationDuration:方法來修改動畫時間,但在這裏我們首先起一個新的事務,於是修改時間就不會有別的副作用。因為修改當前事務的時間可能會導致同一時刻別的動畫(如屏幕旋轉),所以最好還是在調整動畫之前壓入一個新的事務。

修改後的代碼見清單7.2。運行程序,你會發現色塊顏色比之前變得更慢了。

清單7.2 使用CATransaction控制動畫時間

 1 - (IBAction)changeColor
 2 {
 3     //begin a new transaction
 4     [CATransaction begin];
 5     //set the animation duration to 1 second
 6     [CATransaction setAnimationDuration:1.0];
 7     //randomize the layer background color
 8     CGFloat red = arc4random() / (CGFloat)INT_MAX;
 9     CGFloat green = arc4random() / (CGFloat)INT_MAX;
10     CGFloat blue = arc4random() / (CGFloat)INT_MAX;
11     self.colorLayer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;
12     ?//commit the transaction
13     [CATransaction commit];
14 }

如果你用過UIView的動畫方法做過一些動畫效果,那麽應該對這個模式不陌生。UIView有兩個方法,+beginAnimations:context:+commitAnimations,和CATransaction+begin+commit方法類似。實際上在+beginAnimations:context:+commitAnimations之間所有視圖或者圖層屬性的改變而做的動畫都是由於設置了CATransaction的原因。

在iOS4中,蘋果對UIView添加了一種基於block的動畫方法:+animateWithDuration:animations:。這樣寫對做一堆的屬性動畫在語法上會更加簡單,但實質上它們都是在做同樣的事情。

CATransaction+begin+commit方法在+animateWithDuration:animations:內部自動調用,這樣block中所有屬性的改變都會被事務所包含。這樣也可以避免開發者由於對+begin+commit匹配的失誤造成的風險。

事務(隱式動畫)