iOS學習——核心動畫 1、什麼是核心動畫 Core Animation(核心動畫)是一組功能強大、效果華麗的動畫API,無論在iOS系統或者在你開發的App中,都有大量應用。核心動畫所在的位置如下圖所示,可以看到,核心動畫位於UIKit的下一層,相比UIView動畫,它可以實現更複雜的動畫效果。 ...
iOS學習——核心動畫
1、什麼是核心動畫
Core Animation(核心動畫)是一組功能強大、效果華麗的動畫API,無論在iOS系統或者在你開發的App中,都有大量應用。核心動畫所在的位置如下圖所示,可以看到,核心動畫位於UIKit的下一層,相比UIView動畫,它可以實現更複雜的動畫效果。
核心動畫作用在CALayer(Core animation layer)上,CALayer的概念、作用以及layer與UIView的區別在上一篇文章中有詳細的描述,想瞭解的朋友可以參見 iOS學習——核心動畫之Layer基礎,我們可以將UIView看成是一種特殊的CALayer(可以響應事件)。實際上,每一個view都有其對應的layer,這個layer是root layer:
@property (nonatomic, readonly, strong) CALayer *layer;
給view加上動畫,本質上是對其layer進行操作,layer包含了各種支持動畫的屬性,動畫則包含了屬性變化的值、變化的速度、變化的時間等等,兩者結合產生動畫的過程。核心動畫和UIView動畫的對比:UIView動畫可以看成是對核心動畫的封裝,和UIView動畫不同的是,通過核心動畫改變layer的狀態(比如position),動畫執行完畢後實際上是沒有改變的(錶面上看起來已改變)。總體來說核心動畫的優點有:
1)性能強大,使用硬體加速,可以同時向多個圖層添加不同的動畫效果
2)介面易用,只需要少量的代碼就可以實現複雜的動畫效果。
3)運行在後臺線程中,在動畫過程中可以響應交互事件(UIView動畫預設動畫過程中不響應交互事件)。
4)CoreAnimation是跨平臺
的,既可以支持IOS,也支持MAC OS
2、核心動畫類的層次結構
- CAAnimation是所有動畫對象的父類,實現CAMediaTiming協議,負責控制動畫的時間、速度和時間曲線等等,是一個抽象類,不能直接使用。
- CAPropertyAnimation :是CAAnimation的子類,它支持動畫地顯示圖層的keyPath,一般不直接使用。
- CASpringAnimation是iOS9.0之後新增的類,它實現彈簧效果的動畫,是CABasicAnimation的子類。
- CAAnimationGroup使用Group可以將多個動畫合併一起加入到層中,Group中所有動畫併發執行,可以方便地實現需要多種類型動畫的場景。
- CATransition 主要用於轉場動畫從一個場景以動畫的形式過渡到另一個場景,比如Nav的預設Push視圖的效果就是通過CATransition的kCATransitionPush類型來實現。
綜上,核心動畫類中可以直接使用的類有:
CABasicAnimation
CAKeyframeAnimation
CATransition
CAAnimationGroup
CASpringAnimation
3、 簡單使用CoreAnimation的步驟
使用CoreAnimation做動畫的時候,遵循四步就好
- 創建CAAnmation子對象,因為CAAnmation是抽象類,所以一般要使用自具體子類,就是上面說的五類
- 設置CAAnmation的屬性,不同的動畫類別屬性參數不一樣的
- 調用CALayer的addAnimation:forKey:將CAAnimation對象添加到CALayer上,就能執行動畫
- 調用CALayer的removeAnimationForKey方法可以停止CALayer中的動畫。
4、CABasicAnimation和CAKeyframeAnimation
CABasicAnimation和CAKeyframeAnimation都是CAPropertyAnimation的子類,這兩類動畫有著相似的地方,但是也有不同的地方。
- 這兩類動畫有相似的地方,就是這兩類動畫都是通過描繪路徑來形成動畫
- CABasicAnimation通過設定起始點,終點,時間,動畫會沿著你這設定點進行移動
- CAKeyFrameAnimation則可以設置路徑為更多的點構成的路徑,動畫會沿著我們設置的多個點進行移動。
- CABasicAnimation可以看成是只有兩個點的特殊的CAKeyFrameAnimation動畫
這其中主要的參數有:
屬性 | 解釋 |
---|---|
duration | 動畫的持續時間 |
repeatCount | 動畫持續次數,最大次數用MAXFLOAT |
repeatDuration | 設置動畫的時間,在該時間內動畫一直執行,不計次數 |
beginTime | 指定動畫開始的時間。從開始延遲幾秒的話,設置為CACurrentMediaTime() + 秒數 的方式 |
timingFunction | 設置動畫的速度變化 |
fillMode | 動畫在開始和結束時的動作,預設值是 kCAFillModeRemoved |
autoreverses | 動畫結束時是否執行逆動畫 |
fromValue | 所改變屬性的起始值(CABasicAnimation獨有) |
toValue | 所改變屬性的結束時的值(CABasicAnimation獨有) |
byValue | 所改變屬性相同起始值的改變數(CABasicAnimation獨有) |
values |
關鍵幀數組對象,裡面每一個元素即為一個關鍵幀,動畫會在對應的時間段內,依次執行數組中每一個關鍵幀的動畫(CAKeyframeAnimation獨有) |
keyTimes |
上面values設定了路徑上的關鍵點,本參數則設定關鍵點之間的路徑段上所需的時間,所以keyTimes的個數應該比values的個數小1(CAKeyframeAnimation獨有) |
timingFunctions |
同上keyTimes的含義,及設置每一小段路徑上的動畫的變化速率(CAKeyframeAnimation獨有) |
path | 可以直接設置動畫路徑(CAKeyframeAnimation獨有) |
KeyPath常用的屬性:
KeyPath值 | 說明 | 使用形式- swift 3.0 |
---|---|---|
transform.scale | 比例縮放 | 0.8 |
transform.scale.x | 縮放寬的比例 | 0.8 |
transform.scale.y | 縮放高的比例 | 0.8 |
transform.rotation.x | 圍繞x軸旋轉 | 2 * M_PI |
transform.rotation.y | 圍繞y軸旋轉 | 2 * M_PI |
transform.rotation.z | 圍繞z軸旋轉 | 2 * M_PI |
backgroundColor | 背景顏色的變化 | UIColor.red.cgColor |
bounds | 大小縮放,中心不變 | NSValue(cgRect: CGRect(x: 800, y: 500, width: 90, height: 30)) |
position | 位置(中心點的改變) | NSValue(cgPoint: CGPoint(x: 40, y: 240)) |
contents | 內容,比如UIImageView的圖片 | UIImage(named: "to")?.cgImage |
opacity | 透明度 | 0.4 |
contentsRect.size.width | 橫向拉伸縮放 | 0.6 |
contentsRect.size.height | 縱向拉伸縮放 | 0.5 |
timingFunction主要有五種類別:
- kCAMediaTimingFunctionLinear,在整個動畫時間內動畫都是以一個相同的速度來改變,也就是勻速運動。一個線性的計時函數,同樣也是CAAnimation的timingFunction屬性為空時候的預設函數。線性步調對於那些立即加速並且保持勻速到達終點的場景會有意義(例如射出槍膛的子彈)。
- kCAMediaTimingFunctionEaseIn:動畫開始時會較慢,之後動畫會加速,一個慢慢加速然後突然停止的方法。對於之前提到的自由落體的例子來說很適合,或者比如對準一個目標的導彈的發射。
- kCAMediaTimingFunctionEaseOut:動畫在開始時會較快,之後動畫速度減慢,它以一個全速開始,然後慢慢減速停止。它有一個削弱的效果,應用的場景比如一扇門慢慢地關上,而不是砰地一聲。
- kCAMediaTimingFunctionEaseInEaseOut:動畫在開始和結束時速度較慢,中間時間段內速度較快。創建了一個慢慢加速然後再慢慢減速的過程。這是現實世界大多數物體移動的方式,也是大多數動畫來說最好的選擇。如果只可以用一種緩衝函數的話,那就必須是它了。那麼你會疑惑為什麼這不是預設的選擇,實際上當使用UIView的動畫方法時,他的確是預設的,但當創建CAAnimation的時候,就需要手動設置它了。
- kCAMediaTimingFunctionDefault:它和kCAMediaTimingFunctionEaseInEaseOut很類似,但是加速和減速的過程都稍微有些慢。它和kCAMediaTimingFunctionEaseInEaseOut的區別很難察覺,可能是蘋果覺得它對於隱式動畫來說更適合(然後對UIKit就改變了想法,而是使用kCAMediaTimingFunctionEaseInEaseOut作為預設效果),雖然它的名字說是預設的,但還是要記住當創建顯式的CAAnimation它並不是預設選項(換句話說,預設的圖層行為動畫用kCAMediaTimingFunctionDefault作為它們的計時方法)。
fillMode主要有四種類型:
- kCAFillModeForwards :動畫開始之後layer的狀態將保持在動畫的最後一幀,而removedOnCompletion的預設屬性值是 YES,所以為了使動畫結束之後layer保持結束狀態,應將removedOnCompletion設置為NO。
- kCAFillModeBackwards :將會立即執行動畫的第一幀,不論是否設置了 beginTime屬性。觀察發現,設置該值,剛開始視圖不見,還不知道應用在哪裡。
- kCAFillModeBoth:該值是 kCAFillModeForwards 和 kCAFillModeBackwards的組合狀態
- kCAFillModeRemoved:動畫將在設置的 beginTime 開始執行(如沒有設置beginTime屬性,則動畫立即執行),動畫執行完成後將會layer的改變恢複原狀。
/* CABasicAnimation應用 心跳效果 思路:就是讓一張圖片做一個放大縮放小的動畫. */ //代碼實現: - (void) viewDidLoad { CABasicAnimation *anim =[CABasicAnimation animation]; //設置縮放屬性 anim.keyPath = @"transform.scale"; //縮放到一半 anim.toValue = @0.5; //設置動畫執行的次數 anim.repeatCount = MAXFLOAT; //設置動畫執行的時長 anim.duration = 0.25; //設置動畫自動反轉(怎麼去, 怎麼回) anim.autoreverses = YES; //添加動畫 [self.heartView.layer addAnimation:anim forKey:nil]; }
/* CAKeyframeAnimation的應用 圖片抖動 思路:其實就是做一個左右旋轉的動畫.先讓它往左邊旋轉-5,再往右邊旋轉5度,再從5度旋轉到-5度. 就會有左右搖擺的效果了. */ //圖標抖動代碼實現 - (void)values{ //創建一個幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animation]; //設置屬性 anim.keyPath = @"transform.rotation"; //設置屬性值. anim.values = @[@(angle2Rad(-5)),@(angle2Rad(5)),@(angle2Rad(-5))]; //設置執行的次數 anim.repeatCount = MAXFLOAT; anim.duration = 0.25; //添加動畫 [self.iconV.layer addAnimation:anim forKey:nil]; }
//我們還可以直接設置關鍵幀CAKeyframeAnimation動畫的路徑 path屬性 -(void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ //創建一個幀動畫 CAKeyframeAnimation *anim = [CAKeyframeAnimation animation]; //設置屬性 anim.keyPath = @"position"; //直接設置動畫的路徑path是畫弧 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 300, 400)]; anim.path = path.CGPath; //設置執行的次數 anim.repeatCount = MAXFLOAT; //設置是否反轉 anim.autoreverses = YES; anim.duration = 1; //添加動畫 [self.iconV.layer addAnimation:anim forKey:nil]; }
5、 CATransition轉場動畫
iOS中實現轉場動畫有兩種方式,一種是通過我們今天學的CATransition轉場動畫進行,還有一種則是通過UIView的動畫進行。CAKeyframeAnimation的重要屬性:
type:過渡動畫的類型
//轉場類型,字元串類型參數.系統提供了四中動畫形式:
//kCATransitionFade//淡出效果//kCATransitionMoveIn//新視圖移動到舊視圖上//kCATransitionPush//新視圖推出舊視圖//kCATransitionReveal//移開舊視圖顯示新視圖//另外,除了系統給的這幾種動畫效果,我們還可以使用系統私有的動畫效果:
//@"cube",//立方體翻轉效果
//@"oglFlip",//翻轉效果
//@"suckEffect",//收縮效果,動畫方向不可控
//@"rippleEffect",//水滴波紋效果,動畫方向不可控
//@"pageCurl",//向上翻頁效果
//@"pageUnCurl",//向下翻頁效果
//@"cameralIrisHollowOpen",//攝像頭打開效果,動畫方向不可控
//@"cameraIrisHollowClose",//攝像頭關閉效果,動畫方向不可控
subtype:設置轉場方向
//轉場方向,系統一共提供四個方向: //kCATransitionFromRight//從右開始 //kCATransitionFromLeft//從左開始 //kCATransitionFromTop//從上開始 //kCATransitionFromBottom//從下開始
startProgress:開始進度,預設0.0.如果設置0.3,那麼動畫將從動畫的0.3的部分開始
endProgress:結束進度,預設1.0.如果設置0.6,那麼動畫將從動畫的0.6部分以後就會結束
-(void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ //UIView執行轉場動畫 [UIView transitionWithView:self.imageV duration:1 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ _i++; if (_i > 3) { _i = 1; } NSString *imageName = [NSString stringWithFormat:@"%d",_i]; self.imageV.image = [UIImage imageNamed:imageName]; } completion:nil]; }
-(void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ //轉場代碼必須得要和轉場動畫在同一個方法當中. //創建動畫 CATransition *anim = [CATransition animation]; //設置轉場類型 anim.type = @"cube"; //設置轉場的方向 anim.subtype = kCATransitionFromTop; //設置動畫的開始點. anim.startProgress = 0.2; //設置動畫的結束點. anim.endProgress = 0.8; [self.imageV.layer addAnimation:anim forKey:nil]; //轉場代碼必須得要和轉場動畫在同一個方法當中. _i++; if (_i > 3) { _i = 1; } NSString *imageName = [NSString stringWithFormat:@"%d",_i]; self.imageV.image = [UIImage imageNamed:imageName]; }
6、CASpringAnimation
CASpringAnimation是iOS9新加入動畫類型,是CABasicAnimation的子類,用於實現彈簧動畫。CASpringAnimation的重要屬性:
- mass:質量(影響彈簧的慣性,質量越大,彈簧慣性越大,運動的幅度越大)
- stiffness:彈性繫數(彈性繫數越大,彈簧的運動越快)
- damping:阻尼繫數(阻尼繫數越大,彈簧的停止越快)
- initialVelocity:初始速率(彈簧動畫的初始速度大小,彈簧運動的初始方向與初始速率的正負一致,若初始速率為0,表示忽略該屬性)
- settlingDuration:結算時間(根據動畫參數估算彈簧開始運動到停止的時間,動畫設置的時間最好根據此時間來設置)
- (void)springAni { CASpringAnimation * ani = [CASpringAnimation animationWithKeyPath:@"bounds"]; ani.mass = 10.0; //質量,影響圖層運動時的彈簧慣性,質量越大,彈簧拉伸和壓縮的幅度越大 ani.stiffness = 5000; //剛度繫數(勁度繫數/彈性繫數),剛度繫數越大,形變產生的力就越大,運動越快 ani.damping = 100.0;//阻尼繫數,阻止彈簧伸縮的繫數,阻尼繫數越大,停止越快 ani.initialVelocity = 5.f;//初始速率,動畫視圖的初始速度大小;速率為正數時,速度方向與運動方向一致,速率為負數時,速度方向與運動方向相反 ani.duration = ani.settlingDuration; ani.toValue = [NSValue valueWithCGRect:self.centerShow.bounds]; ani.removedOnCompletion = NO; ani.fillMode = kCAFillModeForwards; ani.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [self.cartCenter.layer addAnimation:ani forKey:@"boundsAni"]; }
7、CAAnimationGroup
使用Group可以將多個動畫合併一起加入到層中,Group中所有動畫併發執行,可以方便地實現需要多種類型動畫的場景。
-(void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ CAAnimationGroup *group = [CAAnimationGroup animation]; //縮放 CABasicAnimation *scaleAnim = [CABasicAnimation animation]; //設置屬性 scaleAnim.keyPath = @"transform.scale"; scaleAnim.toValue = @0.5; //平移 CABasicAnimation *Anim = [CABasicAnimation animation]; //設置屬性 Anim.keyPath = @"position.y"; Anim.toValue = @(400); //將上面兩個動畫添加到動畫組 group.animations = @[scaleAnim,Anim]; //設置動畫的屬性,一定要在動畫組上設置 group.removedOnCompletion = NO; group.fillMode = kCAFillModeForwards; //添加動畫 [self.redView.layer addAnimation:group forKey:nil]; }
參考資料:
iOS動畫-從不會到熟練應用