iOS核心動畫高級技巧:第二部分-動畫

傳送門:《iOS核心動畫高級技巧》部分源碼

CA利用RunLoop收集圖層 Animatable屬性 的修改(如backgroundColor等),并基于事務對【隱式動畫】進行管理;簡單來說隱式動畫只能完成部分基礎屬性動畫,而【顯式動畫】則通過 關鍵幀動畫、動畫組 對屬性動畫提供更具體的控制或組合,通過 過渡 支持 NonAnimatable屬性和圖層樹的變化;而【圖層時間】介紹了Core Animation用來操作時間控制動畫的機制:CAMediaTiming協議和層級關系時間,并給出了手動動畫的通用解決方案;【緩沖】通過控制 速度 使動畫更平滑更自然;如果需要實時控制動畫/更強的交互控制動畫,可以使用【基于定時器的動畫】。
 
從結構上來說,CAAnimation包括計時函數(CAMediaTimingFunction)、一個圖層委托(CALayerDelegate,用于反饋動畫狀態)和一個removedOnCompletion(標識動畫是否該在結束后自動釋放,默認YES ,為了防止內存泄露),另外還實現了以下協議:
  - CAAction (允許 CAAnimation 的子類提供圖層行為)
  - CAMediaTiming (第九章“圖層時間”將會詳細解釋)。

我發現一個很奇怪的問題:使用animation.beginTime有時導致動畫失效、有時類似無序的timeOffset,未能實現延遲開始動畫的功能???


一些常用的緩沖函數:
RBBAnimation
AHEasing

第七章:隱式動畫

隱式動畫:Core Animation在每個 RunLoop 周期中自動開始一次新的事務(RunLoop是iOS負責收集用戶輸入、處理定時器或者網絡事件并且重新繪制屏幕的東西),即使不顯式調用[CATransaction begin];開始一次事務,任何在一次RunLoop循環中Animatable屬性的改變也會被集中起來,然后Core Animation根據圖層行為和事務設置(默認0.25秒)去不斷更新視圖的這些屬性在屏幕上的狀態。

  • 呈現和模型
    • 呈現樹 - 圖層的當前位置
      • -presentationLayer
      • 呈現圖層實際上是模型圖層的復制,但是它的屬性值代表了在任何指定時刻當前外觀效果。換句話說,你可以通過呈現圖層的值來獲取當前屏幕上真正顯示出來的值
      • 呈現圖層僅僅當圖層首次被提交(就是第一次在屏幕上顯示)的時候創建,所以在那之前調用-presentationLayer將會返回nil。
      • 需要使用呈現圖層的兩種情況:
        • 同步動畫 - 如果你在實現一個基于定時器的動畫(見第11章“基于定時器的動畫”),而不僅僅是基于事務的動畫,這個時候準確地知道在某一時刻圖層顯示在什么位置就會對正確擺放圖層很有用了。
        • 處理用戶交互 - 如果你想讓你做動畫的圖層響應用戶輸入,你可以使用-hitTest:方法來判斷指定圖層是否被觸摸,這時候對呈現圖層而不是模型圖層調用-hitTest:會顯得更有意義,因為呈現圖層代表了用戶當前看到的圖層位置,而不是當前動畫結束之后的位置。
    • 模型樹 - 圖層將要到達的位置
      • –modelLayer
      • 當設置CALayer的屬性,實際上是在定義當前事務結束之后圖層如何顯示的模型。

第八章:顯式動畫

8.1 CAAnimation體系結構

-(void)applyBasicAnimation:(CABasicAnimation *)animation toLayer:(CALayer *)layer{
  animation.fromValue = [layer.presentationLayer ?: layer valueForKeyPath:animation.keyPath];
 
  // note: this approach will only work if toValue != nil
  [CATransaction begin];
  [CATransaction setDisableActions:YES];
  [layer setValue:animation.toValue forKeyPath:animation.keyPath];
  [CATransaction commit];
 
  [layer addAnimation:animation forKey:nil];
}
        - 在動畫之后更新(需結合KVC和fillMode) - CAAnimationDelegate
-(void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag
{
  // CAAnimation實現了KVC(鍵-值-編碼)協議,于是你可以用-setValue:forKey:和-valueForKey:方法來存取屬性。
  // 可以利用它來判斷到底是哪個圖層的調用
  // 另外,為了確保更新屬性更新發生在動畫返回初始狀態之前,還得考慮fillMode?。?!
  [CATransaction begin];
  [CATransaction setDisableActions:YES];
  self.colorLayer.backgroundColor = (__bridge CGColorRef)anim.toValue;
  [CATransaction commit];
}
  • 2-CAKeyframeAnimation
    • 虛擬屬性 - transform.rotation
      • Core Animation自動通過CAValueFunction計算的值來更新屬性
      • 我們可以不通過關鍵幀一步旋轉多于180度的動畫。
      • 可以用相對值而不是絕對值旋轉(設置byValue而不是toValue)。
      • 可以不用創建CATransform3D,而是使用一個簡單的數值來指定角度。
      • 不會和transform.position或者transform.scale沖突(同樣是使用關鍵路徑來做獨立的動畫屬性)。
  • 8.1.2 CAAnimationGroup - 動畫組
  • 8.1.3 CATransition - 過渡
    • 影響整個圖層,可以用來對圖層的任何內容做任何類型的動畫,包括子圖層的添加和移除。
kCATransitionFade //平滑的淡入淡出效果
 
kCATransitionPush  //從頂部滑動進入,但不像推送動畫那樣把老圖層推走
kCATransitionMoveIn //新圖層從邊緣的一側滑動進來,把舊圖層從另一側推出去的效果
kCATransitionReveal  //把原始的圖層滑動出去來顯示新的外觀,而不是把新的圖層滑動進入
+ [subtype](https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CATransition_class/index.html#//apple_ref/occ/instp/CATransition/subtype) - kCATransitionFromRight/Top/Left/Bottom
+ 對指定的圖層一次只能使用一次CATransition
[self.imageView.layer addAnimation:transition forKey:nil];  //使用默認鍵 - kCATransition
  • 隱式過渡

    • 對于你自己創建的圖層,這意味著對圖層contents圖片做的改動都會自動附上淡入淡出的動畫。
    • 對于視圖關聯的圖層,或者是其他隱式動畫的行為,這個特性依然是被禁用的
  • 自定義動畫

    • UIView的兩個方法提供了Core Animation的過渡特性
+transitionFromView:toView:duration:options:completion://可能有圖層樹變化
+transitionWithView:duration:options:animations://圖層樹不變
  • CALayer有一個-renderInContext:方法,可以通過把它繪制到Core Graphics的上下文中捕獲當前內容的圖片,然后把這個截屏視圖置于原始視圖之上,遮住真實視圖的所有變化,于是創建了一個簡單的過渡效果
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *coverImage = UIGraphicsGetImageFromCurrentImageContext();
  • -renderInContext:捕獲了圖層的圖片和子圖層,但是不能對子圖層正確地處理變換效果,而且對視頻和OpenGL內容也不起作用。但是用CATransition,或者用私有的截屏方式就沒有這個限制了???

8.2 在動畫過程中取消動畫

  • 注意:動畫一旦被移除,圖層的外觀就立刻更新到當前的模型圖層的值

第九章:圖層時間

Core Animation是如何跟蹤時間的

  • CAMediaTiming協議
  • CALayer和CAAnimation都實現了這個協議,所以動畫時間可以被任意基于一個圖層或者一段動畫的類控制。
  • 層級關系時間
  • 全局時間和本地時間
    • 全局時間 - 設備休眠時會暫停
CFTimeInterval time = CACurrentMediaTime(); // 馬赫時間:對動畫的時間測量提供了一個相對值
  • 本地時間
    每個CALayer和CAAnimation實例都有自己本地時間的概念,是根據父圖層/動畫層級關系中的beginTime,timeOffsetspeed屬性計算。下述方法用來同步不同圖層之間有不同的 speed,timeOffsetbeginTime 的動畫:
-(CFTimeInterval)convertTime:(CFTimeInterval)t from/toLayer:(CALayer *)l;

第十章:緩沖

使動畫移動更平滑更自然


第十一章:基于定時器的動畫

允許我們精確地控制一幀一幀展示;iOS按照每秒60次刷新屏幕,CAAnimation最機智的地方在于每次刷新需要展示的時候去計算插值和緩沖。

  • 定時幀
  • NSTimer
    受RunLoop中的任務列表影響,可能會有很大的延遲
    優化:
    • 我們可以用CADisplayLink讓更新頻率嚴格控制在每次屏幕刷新之后。
    • 基于真實幀的持續時間而不是假設的更新頻率來做動畫。
    • 調整動畫計時器的run loop模式,這樣就不會被別的事件干擾。
  • CADisplayLink
    • 不能保證每一幀都按計劃執行,一些失去控制的離散的任務或者事件(例如資源緊張的后臺程序)可能會導致動畫偶爾地丟幀。當使用NSTimer的時候,一旦有機會計時器就會開啟,但是CADisplayLink卻不一樣:如果它丟失了幀,就會直接忽略它們,然后在下一次更新的時候接著運行。
    • 計算幀的持續時間
      然后根據緩沖函數計算下一幀的目標位置,達到精確控制、動畫平滑
  • 物理模擬
    • Chipmunk
      • 基礎類
      • cpSpace - 所有的物理結構體的容器 (一個大小和一個可選的重力矢量)
      • cpBody - 固態無彈力的剛體 (坐標+其他物理屬性,例如質量,運動和摩擦系數等等)
      • cpShape - 抽象的幾何形狀,有各種子類代表不同形狀 (比如cpPolyShape),可以給結構體添加一個多邊形用來檢測碰撞。
      • 添加用戶交互
        • cpShapeSetCollisionType
        • cpSpaceAddStaticShape
      • 模擬時間以及固定的時間步長
        根據屏幕刷新的時間跟蹤時間步長,然后根據每幀去計算一個或者多個模擬出來的效果。
        • 對于實現動畫的緩沖效果來說,計算每幀持續的時間是一個很好的解決方案
        • 對模擬物理效果則應該使用固定的時間步長
while (self.lastStep < frameTime) {
  cpSpaceStep(self.space, SIMULATION_STEP);
  self.lastStep += SIMULATION_STEP;
}
- 避免死亡螺旋
 + cpSpaceStep()的計算造成幀率延遲的塔羅牌堆積效應
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,544評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,133評論 5 13
  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,313評論 0 6
  • 顯式動畫 顯式動畫,它能夠對一些屬性做指定的自定義動畫,或者創建非線性動畫,比如沿著任意一條曲線移動。 屬性動畫 ...
    清風沐沐閱讀 1,959評論 1 5
  • 前言 本文只要描述了iOS中的Core Animation(核心動畫:隱式動畫、顯示動畫)、貝塞爾曲線、UIVie...
    GitHubPorter閱讀 3,646評論 7 11