21- 《A GUIDE TO IOS ANIMATION 2.0》(楊騎滔)三章.CoreAnimation-學習筆記: 源碼分析和盲點記錄
第一個案例: Twitter 的啟動動畫
這個案例之前有看過.當時覺得很有意思. 今天看了楊騎滔給出的實現思路之后,才發現實現代碼不難,難的還是你的實現的思路. 我們仔細觀察,書中的啟動動畫,開始的頁面是從程序啟動之后一直到進入根控制器都是同一個,而且明顯,要比我們平時的啟動界面停留的時間要長.這個的實現思路和我們看到的很多主流APP進入之后,會有一個廣告界面,還有倒計時.這個肯定是系統自帶的LaunchScreen.xib
啟動完成之后,在顯示根控制器之前穿插的. 只不過,廣告和啟動是不同的頁面,我們這里是需要兩個樣式一模一樣的頁面.
原理,我就不贅述了.我想看了書的人和看了源碼的人早已經了然于胸. 現在只是記錄下自己的知識的盲點.
UIWindow的兩個方法
[self.window makeKeyAndVisible];
和 self.window.rootViewController
的具體作用:
-------- 占位行 ------------
mask屬性
“在開始之前,我們先了解一下 Layer 的 mask 屬性。
@property(strong) CALayer *mask;
可以發現 mask 也是一個 CALayer”
--- 摘錄來自: 楊騎滔(KittenYang). “A GUIDE TO IOS ANIMATION”。 iBooks.
//logo mask 添加一個遮罩,圖片透明和不透明的地方反轉
CALayer *maskLayer = [CALayer layer];
maskLayer.contents = (id)[UIImage imageNamed:@"1"].CGImage; //必須是CGImageRef
maskLayer.position = navc.view.center;
maskLayer.bounds = CGRectMake(0, 0, 60, 60);
navc.view.layer.mask = maskLayer; //為mask(CALayer)屬性賦值之后,露出window是黑色的,必須通過改變self.window.background的顏色
CoreAnimation - CAKeyframeAnimation
---- 以下均為原文,摘錄來自: 楊騎滔(KittenYang). “A GUIDE TO IOS ANIMATION”。 iBooks.
- 顧名思義,CAKeyframeAnimation 就相當于 Flash 里的關鍵幀動畫”
- CAKeyframeAnimation 中我們通過 keyPath 就可以指定動畫的類型。”
- 然后,我們把每個關鍵幀的對應參數賦值給 CAKeyframeAnimation 的 values 屬性。代碼中,我設置了3個關鍵幀,transformAnimation.values = xxx
- 設置對應的時間點 transformAnimation.keyTimes = xxx
- 但是我們還要注意。當你給一個 CALayer 添加動畫的時候,動畫其實并沒有改變這個 layer 的實際屬性。取而代之的,系統會創建一個原始 layer 的拷貝。在文檔中,蘋果稱這個原始 layer 為 Model Layer ,而這個復制的 layer 則被稱為 Presentation Layer 。 Presentation Layer 的屬性會隨著動畫的進度實時改變,而 Model Layer 中對應的屬性則并不會改變。所以如果你想要獲取動畫中每個時刻的狀態,請使用 layer 的 func presentationLayer() -> AnyObject!
- 為了讓動畫在結束之后不突然回到了初始狀態, 引出 removedOnCompletion 和 fillMode 了。
removedOnCompletion 的官方解釋是:
/* When true, the animation is removed from the render tree once its- active duration has passed. Defaults to YES. */
也就是默認情況下系統會在 duration 時間后自動移除這個 CAKeyframeAnimation。當 remove 了某個動畫,那么系統就會自動銷毀這個 layer 的 Presentation Layer ,只留下 Model Layer ”
- 你需要先把 removedOnCompletion 設置為 false ,然后設置 fillMode 為kCAFillModeForwards” (TIPS: 對于 CAAnimation ,你需要將其 removedOnCompletion 設置為 false 才行,要不然 fillMode 將不起作用。”)。但設置 removedOnCompletion 和 fillMode 不是正確的方式(這個之后再詳細說明)。
- 所以一個好動畫離不開一堆好參數。
第二個案例: 圓圈遮罩的轉場動畫
這個案例講的是轉場動畫,這個Demo的效果可以看格瓦拉
選中一個條目之后,
關于轉場動畫
“iOS7 開始蘋果推出了自定義轉場的 API 。從此,任何可以用 CoreAnimation 實現的動畫,都可以出現在兩個 ViewController 的切換之間。”
“蘋果在 UINavigationControllerDelegate
和 UIViewControllerTransitioningDelegate
中給出了幾個協議方法,通過返回類型就可以很清楚地知道各自的具體作用。你只需要重載它們,然后 return
一個動畫的實例對象,一切都搞定了。使用準則就是:UINavigationController pushViewController
時重載 UINavigationControllerDelegate 的方法;UIViewController presentViewController
時重載 UIViewControllerTransitioningDelegate
的方法。”
——摘錄來自: 楊騎滔(KittenYang). “A GUIDE TO IOS ANIMATION”。 iBooks.
實現步驟
1.根據第一小節中提到的關于轉場動畫的解釋,是說我們在當天起始跳轉控制器中實現對應的
push
或者present
對應的代理方法.
2.創建繼承自 NSObject 并且聲明 UIViewControllerAnimatedTransitioning 的的動畫類
3.重載 UIViewControllerAnimatedTransitioning 中的協議方法。
就這三步. 具體的轉場效果,在第3步中自行定義,你寫成啥樣的,他就按照給你樣轉
案例分析
再回到我們這個案例.這個效果,其實是兩個有形狀的UIBezierPath的貝塞爾曲線對象的path
值,分別作為CABasicAnimation對象的起始值到終點值. 然后系統內部發生的變化. 參看下邊代碼:
maskLayerAnimation.fromValue = (__bridge id)(maskStartBP.CGPath);
maskLayerAnimation.toValue = (__bridge id)((maskFinalBP.CGPath));
楊騎滔在animateTransition:
方法中,首先獲取到跳轉和跳轉到的控制器,然后把這兩個控制器的view添加到transitionContext.containerView
中,接著創建兩個圓形的UIBezierPath對象,最終的轉成效果類似我們案例一.實現代碼也有類似的地方.
其中,第一個需要注意的地方是:觸發點的判斷,判斷在哪個象限,然后得出出發點的坐標,如果你對象限有點遺忘的話,你可以看下邊這幅圖,馬上就想起來了:
http://blog.csdn.net/ys410900345/article/details/42924827
/** timingFunction
*
* 用于變化起點和終點之間的插值計算,形象點說它決定了動畫運行的節奏,比如是均勻變化(相同時間變化量相同)還是
* 先快后慢,先慢后快還是先慢再快再慢.
*
* 動畫的開始與結束的快慢,有五個預置分別為(下同):
* kCAMediaTimingFunctionLinear 線性,即勻速
* kCAMediaTimingFunctionEaseIn 先慢后快
* kCAMediaTimingFunctionEaseOut 先快后慢
* kCAMediaTimingFunctionEaseInEaseOut 先慢后快再慢
* kCAMediaTimingFunctionDefault 實際效果是動畫中間比較快.
*/