應用中的動畫根據需求確定不多是一成不變的。ios
當動畫進行不一樣的狀態切換的時候咱們須要接下來要作什麼。與見見單單的兩個屏幕畫面跳轉不一樣,動畫須要告訴用戶什麼即將到來而又要到哪裏去。數組
鍵盤事件很好地解釋了動畫是對用戶具備解釋性的屬性。一樣視圖控制器切換也能夠經過大體的方向給用戶提示接下來他/她要去前往哪一個界面。附帶細微得彈簧與碰撞效果提高整個感受效果讓APP更具備生氣。框架
動畫對你的APP而言是一個很好地介紹方式。固然須要懂動畫的基本原理後,那麼你才能更好掌握如何去整動畫。函數
儘管高級UIKit框架中的高級API能夠實現不少動畫,可是仍是從CALayer層入手,由於這正式animation操做的對象。動畫
這裏要知道animation加在一個視圖的layer層不是直接經過改變其屬性來展現動畫效果的。spa
相反,Core Animation
維護了兩套layer層級:數據模型layer層樹和表現layer層樹。前者存放層的狀態然後者展現動畫值。翻譯
試想下一個視圖的淡出動畫。若是你在動畫的任意時間點去查看層透明度值,你將得不到與屏幕所對應的透明度值。相反若你去表現層中獲取將能獲取到正確的透明度值。code
固然你不能直接對錶現層進行直接的賦值,它能夠有效的用來建立新的動畫或在動畫期間能進行很好的互動。orm
經過調用-[CALayer presentationLayer] 與 -[CALayer modelLayer]
,可你能夠在兩種層級結構中輕易切換。對象
動畫不少不少場景基本是視圖的一個屬性值變化從一個值到另一個值,思考以下栗子:
上述火箭的X座標從77變化到了455,已經超過了能展現的區間,爲了能填充全部得動畫幀,咱們須要肯定火箭在任意時間點得位置。一般用線性表達來求得火箭X座標與時間t的關係:
使用CABasicAnimation
,根據以下代碼能夠實現上述描述:
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; [rocket.layer addAnimation:animation forKey:@"basic"];
主要是用KVC,獲取要修改的屬性position.x
。這是CA封好的一個使用起來比較方便得地方。。。(確實比較方便)
由於默認狀況下animation不會直接修改表現層,並在動畫結束的時候被移除掉。一旦動畫被移除了,表現層將會回到初始的狀態。
解決方案有兩個:
第一種方式是直接更新數據層的屬性(推薦),由於這麼作使動畫徹底可選。
一旦動畫結束而且從layer層移除,那麼表現層將會與數據層契合,正好符合動畫的最後一幀。
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; [rocket.layer addAnimation:animation forKey:@"basic"]; rocket.layer.position = CGPointMake(455, 61);
或者你能夠經過給動畫的fillMode
賦值爲kCAFillModeForwards
同時將removedOnCompletion
設置爲NO
來讓動畫保持最後一幀的狀態。可是動畫結束保持表現層與數據層的統一是一個良好得習慣,因此這種方法使用的時候要十分注意。
Andy Matuschak指出若是保持完成的動畫將渲染一些沒必要要的外形帶來額外的消耗。
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; animation.fillMode = kCAFillModeForward; animation.removedOnCompletion = NO; [rectangle.layer addAnimation:animation forKey:@"basic"];
很是有必要說明下每當咱們建立一個動畫對象,它將會爲添加到layer層。這個特色咱們須要記在內心由於當有多個視圖的時候咱們能夠進行重用。若是咱們第二個火箭想再第一個火箭動畫完成後進行發射:
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.byValue = @378; animation.duration = 1; [rocket1.layer addAnimation:animation forKey:@"basic"]; rocket1.layer.position = CGPointMake(455, 61); animation.beginTime = CACurrentMediaTime() + 0.5; [rocket2.layer addAnimation:animation forKey:@"basic"]; rocket2.layer.position = CGPointMake(455, 111);
由於是copy的緣故,上述animation的修改只會影響到後面添加該animation的視圖layer層對象。
CABasicAnimation中的byValue
屬性效果是當你動畫結束的時候變化的屬性值加上某個值(byValue)。這樣的好處使得動畫更容易被複用。這樣咱們不用特別去控制起始值和終止值。
就是兩步以上得動畫。。。這時候咱們可使用泛型動畫CAKeyframeAnimation
。
Keyframes讓咱們能夠隨意的設定咱們動畫的關鍵位置點,並自動爲咱們填充關鍵位置點之間的動畫效果。
舉個輸入密碼,密碼驗證錯誤得動畫效果:
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.keyPath = @"position.x"; animation.values = @[ @0, @10, @-10, @10, @0 ]; animation.keyTimes = @[ @0, @(1 / 6.0), @(3 / 6.0), @(5 / 6.0), @1 ]; animation.duration = 0.4; animation.additive = YES; [form.layer addAnimation:animation forKey:@"shake"];
仍是KVC找出動畫要變更的屬性,經過animation的value屬性提供了中間變化點得值數組外加一個對應動畫變更時間點的時間數組。(這裏略了一段)
這裏先吐槽了下沿着複雜軌跡走須要保存好多好多的座標啊。。。而後說尼瑪幸虧CAKeyframeAnimation
提供了便捷的處理方式。
舉個栗子:
CGRect boundingRect = CGRectMake(-150, -150, 300, 300); CAKeyframeAnimation *orbit = [CAKeyframeAnimation animation]; orbit.keyPath = @"position"; orbit.path = CFAutorelease(CGPathCreateWithEllipseInRect(boundingRect, NULL)); orbit.duration = 4; orbit.additive = YES; orbit.repeatCount = HUGE_VALF; orbit.calculationMode = kCAAnimationPaced; orbit.rotationMode = kCAAnimationRotateAuto; [satellite.layer addAnimation:orbit forKey:@"orbit"];
經過調用類方法咱們建立了一個圓形路徑用來當作動畫路徑。
使用calculationMode
用來控制每一個時間源的幀動畫。設置成kCAAnimationPaced
來保證勻速。
設置rotationMode
來保證動畫貼合軌跡進行適度旋轉。不然動畫以下:
在現實生活中是須要加速以及減速後進入勻速狀態,動畫須要儘可能的真實須要引入時間參數方程來描述加速與減速的過程。
上述已經展現過最簡單得加速方式:線性加速。在CA中這個方程使用CAMediaTimingFunction
類。
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @50; animation.toValue = @150; animation.duration = 1; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; [rectangle.layer addAnimation:animation forKey:@"basic"]; rectangle.layer.position = CGPointMake(150, 0);
CA還內置了一些其餘時間源方程的動畫效果。。此處省略N個字。。。
另外介紹下還能夠根據你想要添加的控制點自定義本身的時間源方程:+functionWithControlPoints::::
。
代碼以下:
CABasicAnimation *animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.fromValue = @77; animation.toValue = @455; animation.duration = 1; animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.5:0:0.9:0.7]; [rocket.layer addAnimation:animation forKey:@"basic"]; rocket.layer.position = CGPointMake(150, 0);
注:貝塞爾曲線是用來畫平滑曲線用的。。。
貝塞爾曲線中的幾個控制點被傳入+functionWithControlPoints::::
(參數範圍是0到1),時間源方程會根據路徑調整當前的速度。
而後做者本身封了一個庫來知足更復雜的動畫效果包括了反彈效果:
RBBTweenAnimation *animation = [RBBTweenAnimation animation]; animation.keyPath = @"position.y"; animation.fromValue = @50; animation.toValue = @150; animation.duration = 1; animation.easing = RBBEasingFunctionEaseOutBounce;
爲了達到某些複雜的效果,可能須要在同一時刻改變一系列得屬性值。
好比同時改變視圖的位置,翻轉以及Z軸得相對位置。此時使用CAAnimationGroup
,咱們能夠這麼寫:
CABasicAnimation *zPosition = [CABasicAnimation animation]; zPosition.keyPath = @"zPosition"; zPosition.fromValue = @-1; zPosition.toValue = @1; zPosition.duration = 1.2; CAKeyframeAnimation *rotation = [CAKeyframeAnimation animation]; rotation.keyPath = @"transform.rotation"; rotation.values = @[ @0, @0.14, @0 ]; rotation.duration = 1.2; rotation.timingFunctions = @[ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; CAKeyframeAnimation *position = [CAKeyframeAnimation animation]; position.keyPath = @"position"; position.values = @[ [NSValue valueWithCGPoint:CGPointZero], [NSValue valueWithCGPoint:CGPointMake(110, -20)], [NSValue valueWithCGPoint:CGPointZero] ]; position.timingFunctions = @[ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; position.additive = YES; position.duration = 1.2; CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; group.animations = @[ zPosition, rotation, position ]; group.duration = 1.2; group.beginTime = 0.5; [card.layer addAnimation:group forKey:@"shuffle"]; card.layer.zPosition = 1;
使用組動畫的好處在於咱們能見分散的動畫用一個對象來控制。這樣的好處在咱們工廠生產出來的對象時候能夠在多處複用咱們的代碼。同時咱們能夠用組動畫在同一時刻進行時間源函數控制。
略。。。 大概是扯皮ios7中的運行時約束限制 以及FB的Pop開源介紹