iOS動畫知識


目錄

  • ** UIView 動畫 **
  • ** Core Animation **
  • ** FaceBook POP動畫 **

在iOS中,圖形可分為以下幾個層次:


<p>OpenGL ES使用硬件加速接口來處理先進的2d 和3d 呈現。OpenGLES通常由游戲開發者或想實現沉浸式圖像體驗的開發者使用。OpenGLES框架提供對呈現過程的全部控制,以及提供創建平滑動畫所需要的幀速。</p>

  • 創建2D和3D圖形
  • 創建更復雜的圖形,比如數據虛擬化、模擬飛行,或者視頻游戲
  • 訪問底層圖形設備

<p>Core Graphics也稱作Quartz,是對定制的2D向量和圖像呈現提供支持的本地繪制引擎。該框架提供的引擎雖然沒有OpenGLES引擎速度快,但該框架能夠很好地適合于呈現定制的2d圖形和動態圖像。</p>

  • 創建基于路徑的繪圖
  • 抗鋸齒渲染
  • 添加梯度、圖片和顏色
  • Use coordinate-space transformations.
  • 創建、顯示和分析PDF文檔

<p>Core Animation也是Quartz核心框架的一部分,是優化應用動畫體驗的基礎技術。使用Core Animation可以創建嵌套的對象,并且可以對它們操作、旋轉、縮放和轉換。使用Core animation,你可以創建動態的用戶界面而不用使用更底層的圖形API,如OpenGL ES。</p>

  • 創建定制動畫
  • 添加定時函數和圖形
  • 支持幀動畫
  • Specify graphical layout constraints.
  • Group multiple-layer changes into anatomic update.

<p>UIKit視圖基于 Core Animation提供視圖級別的動畫支持。</p>

實現動畫三要素

  • 元素(who)
  • 行為(how)
  • 執行(do)

兩個概念

1.仿射變換(Affine Transformation或 Affine Map)

是一種二維坐標到二維坐標之間的線性變換,它保持了二維圖形的“平直性”(即:直線經過變換之后依然是直線)和“平行性”(即:二維圖形之間的相對位置關系保持不變,平行線依然是平行線,且直線上點的位置順序不變)。

  • 變換原理
    <pre><code>struct CGAffineTransform {
    CGFloat a;
    CGFloat b;
    CGFloat c;
    CGFloat d;
    CGFloat tx;
    CGFloat ty;
    };</code></pre>
    結構體矩陣圖為:(矩陣圖)

因為最后一列總是是(0,0,1),所以有用的信息就是前面兩列

對一個view進行仿射變化就相當于對view上的每個點做一個乘法
結果就是:(映射變換)

相當于:
(x, y, 1 ) --> (ax + cy + tx, bx + dy + ty, 1)

如果不看c和b的話

a表示x水平方向的縮放,tx表示x水平方向的偏移

d表示y垂直方向的縮放,ty表示y垂直方向的偏移

如果b和c不為零的話,那么視圖肯定發生了旋轉

<p>仿射變換可以通過一系列的原子變換的復合來實現,包括:平移(Translation)、縮放(Scale)、翻轉(Flip)、旋轉(Rotation)和錯切(Shear)。
</p>

  • 常用函數
    <pre><code>/// 用來連接兩個變換效果并返回。返回的t = t1 * t2
    CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2)

/// 矩陣初始值。[ 1 0 0 1 0 0 ]
CGAffineTransformIdentity

/// 自定義矩陣變換,需要掌握矩陣變換的知識才知道怎么用。參照(x, y, 1 ) --> (ax + cy + tx, bx + dy + ty, 1)
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)

/// 旋轉視圖。傳入參數為 角度 * (M_PI / 180)。等同于 CGAffineTransformRotate(self.transform, angle)
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)

/// 縮放視圖。等同于CGAffineTransformScale(self.transform, sx, sy)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)

/// 平移視圖。等同于CGAffineTransformTranslate(self.transform, tx, ty)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
</code></pre>

2.貝塞爾曲線

是應用于二維圖形應用程序的數學曲線。

曲線定義:起始點、終止點(也稱錨點)、控制點。
通過調整控制點,貝塞爾曲線的形狀會發生變化。

  • 線性貝塞爾曲線
由 P0 至 P1 的連續點, 描述的一條線段
  • 二次貝塞爾曲線
原理:

 由 P0 至 P1 的連續點 Q0,描述一條線段
 由 P1 至 P2 的連續點 Q1,描述一條線段。 
 由 Q0 至 Q1 的連續點 B(t),描述一條二次貝塞爾曲線。
  • 三次貝塞爾曲線

** 通用公式:**

** 高階貝塞爾曲線:**

  • 四次貝塞爾曲線
  • 五次貝塞爾曲線

貝塞爾曲線應用在動畫中,描述物件的運動路徑等等。

UIBezierPath

使用UIBezierPath類可以創建基于矢量的路徑,這個類在UIKit中。此類是Core Graphics框架關于CGPathRef的一個封裝。

path如果是基于矢量形狀的,都用直線和曲線段去創建。 我們使用直線段去創建矩形和多邊形,使用曲線段去創建?。╝rc),圓或者其他復雜的曲線形狀。 每一段都包括一個或者多個點,繪圖命令定義如何去詮釋這些點。每一個直線段或者曲線段的結束的地方是下一個的開始的地方。每一個連接的直線或者曲線段的集合成為subpath。一個UIBezierPath對象定義一個完整的路徑包括一個或者多個subpaths。

使用UIBezierPath畫圖步驟:

  • 1.創建一個UIBezierPath對象
  • 2.調用-moveToPoint:設置初始線段的起點
  • 3.添加線或者曲線去定義一個或者多個子路徑
  • 4.改變UIBezierPath對象跟繪圖相關的屬性。如,我們可以設置畫筆的屬性、填充樣式等

詳情見UIBezierPath_And_CAShapeLayer

===================

一、UIView 動畫

** 可實現動畫的屬性 **
<pre><code>坐標尺寸類: bounds、frame、center
視圖顯示類: backgroundColor、alpha、hidden
形態變化類: transform</code></pre>

1、首尾式

** 基本寫法,代碼必須放在Begin和Commit之間: **
<pre><code>[UIView beginAnimations:nil context:nil]; // 開始動畫
// Code...
[UIView commitAnimations]; // 提交動畫</code></pre>

** 簡單例子:**
<pre><code>[UIView beginAnimations:nil context:nil]; // 開始動畫
[UIView setAnimationDuration:10.0]; // 動畫時長

/**

  • 圖像向下移動
    */
    CGPoint point = _imageView.center;
    point.y += 150;
    [_imageView setCenter:point];

[UIView commitAnimations]; // 提交動畫</code></pre>

**同時運行多個動畫效果: **

<pre><code>[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[_imageView setAlpha:0.0];
[UIView commitAnimations];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
CGPoint point = _imageView.center;
point.y += 150;
[_imageView setCenter:point];
[UIView commitAnimations];</code></pre>
以上代碼實現的動畫效果為(同時執行):

1、圖像向下平移150像像
2、設置圖像透明度為0。

其它方法及屬性:

以下方法及屬性不為全部,只例舉部分:

<pre><code>// 開始動畫

  • (void)beginAnimations:(NSString *)animationID context:(void *)context;

// 提交動畫

  • (void)commitAnimations;

// 設置動畫曲線,默認是勻速進行:

  • (void)setAnimationCurve:(UIViewAnimationCurve)curve;

// 設置動畫時長:

  • (void)setAnimationDuration:(NSTimeInterval)duration;

// 默認為YES。為NO時跳過動畫效果,直接跳到執行后的狀態。

  • (void)setAnimationsEnabled:(BOOL)enabled;

// 設置動畫延遲執行(delay:秒為單位):

  • (void)setAnimationDelay:(NSTimeInterval)delay;

// 動畫的重復播放次數

  • (void)setAnimationRepeatCount:(float)repeatCount;

// 如果為YES,逆向(相反)動畫效果,結束后返回動畫逆向前的狀態; 默認為NO:

  • (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;

// 設置動畫代理:

  • (void)setAnimationDelegate:(id)delegate;

// 動畫將要開始時執行方法××(必須要先設置動畫代理):

  • (void)setAnimationWillStartSelector:(SEL)selector;

// 動畫已結束時執行方法××(必須要先設置動畫代理):

  • (void)setAnimationDidStopSelector:(SEL)selector;

/**

  • 設置動畫過渡效果
  • @param transition 動畫的過渡效果
  • @param view 過渡效果作用視圖
  • @param cache 如果為YES,開始和結束視圖分別渲染一次并在動畫中創建幀;否則,視圖將會渲染每一幀。例如,你不需要在視圖轉變中不停的更新,你只需要等到轉換完成再去更新視圖。
    */
  • (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;

轉場類型
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
</code></pre>

2、block:

  • 方法一:
    <pre><code>[UIView animateWithDuration:4.0 // 動畫時長
    animations:^{
    // code
    }];</code></pre>

  • 方法二:
    <pre><code>[UIView animateWithDuration:4.0 // 動畫時長
    animations:^{
    // code...
    }
    completion:^(BOOL finished) {
    // 動畫完成后執行
    // code...
    }];</code></pre>

  • 方法三:

<pre><code>[UIView animateWithDuration:4.0 // 動畫時長
delay:2.0 // 動畫延遲
options:UIViewAnimationOptionCurveEaseIn // 動畫過渡效果
animations:^{
// code...
}
completion:^(BOOL finished) {
// 動畫完成后執行
// code...
}];</code></pre>

  • 方法四,Spring Animationring Animation):彈簧動畫

在IOS7開始,系統動畫效果廣泛應用Spring Animation:

<pre><code>[UIView animateWithDuration:4.0 // 動畫時長
delay:0.0 // 動畫延遲
usingSpringWithDamping:1.0 // 類似彈簧振動效果 0~1
initialSpringVelocity:5.0 // 初始速度
options:UIViewAnimationOptionCurveEaseInOut // 動畫過渡效果
animations:^{
// code...
CGPoint point = _imageView.center;
point.y += 150;
[_imageView setCenter:point];
} completion:^(BOOL finished) {
// 動畫完成后執行
// code...
[_imageView setAlpha:1];
}];
</code></pre>
usingSpringWithDamping:它的范圍為 0.0f 到 1.0f ,數值越小「彈簧」的振動效果越明顯。
initialSpringVelocity:初始的速度,數值越大一開始移動越快。值得注意的是,初始速度取值較高而時間較短時,也會出現反彈情況。

轉:Spring Animation 是線性動畫或 ease-out 動畫的理想替代品。由于 iOS 本身大量使用的就是 Spring Animation,用戶已經習慣了這種動畫效果,因此使用它能使 App 讓人感覺更加自然,用 Apple 的話說就是「instantly familiar」。此外,Spring Animation 不只能對位置使用,它適用于所有可被添加動畫效果的屬性。
  • 方法六,關鍵幀動畫:

    UIView動畫已經具備高級的方法來創建動畫,而且可以更好地理解和構建動畫。IOS7以后蘋果新加了一個animateKeyframesWithDuration的方法,我們可以使用它來創建更多更復雜更酷炫的動畫效果,而不需要去使用到核心動畫(CoreAnimation)。

創建關鍵幀方法:

<pre><code>/**

  • 添加關鍵幀方法
  • @param duration 動畫時長
  • @param delay 動畫延遲
  • @param options 動畫效果選項
  • @param animations 動畫執行代碼
  • @param completion 動畫結束執行代碼
    */
  • (void)animateKeyframesWithDuration:(NSTimeInterval)duration
    delay:(NSTimeInterval)delay
    options:(UIViewKeyframeAnimationOptions)options
    animations:(void (^)(void))animations
    completion:(void (^)(BOOL finished))completion;
    </code></pre>

添加關鍵幀方法:

<pre><code>/**

  • 添加關鍵幀
  • @param frameStartTime 動畫相對開始時間
  • @param frameDuration 動畫相對持續時間
  • @param animations 動畫執行代碼
    */
  • (void)addKeyframeWithRelativeStartTime:(double)frameStartTime
    relativeDuration:(double)frameDuration
    animations:(void (^)(void))animations;
    </code></pre>以上說的相對時間,也就是說:“它們自身會根據動畫總持續時長自動匹配其運行時長”。

<pre><code>[UIView animateKeyframesWithDuration:4.0
delay:0.0
options:UIViewKeyframeAnimationOptionCalculationModeCubic | UIViewAnimationOptionCurveLinear
animations:keyFrameBlock
completion:^(BOOL finished) {
// 動畫完成后執行
// code...
}];
</code></pre>
動畫過渡效果(Options),新增了以下幾個:
<pre><code>UIViewKeyframeAnimationOptionCalculationModeLinear = 0 << 10, // default
UIViewKeyframeAnimationOptionCalculationModeDiscrete = 1 << 10,
UIViewKeyframeAnimationOptionCalculationModePaced = 2 << 10,
UIViewKeyframeAnimationOptionCalculationModeCubic = 3 << 10,
UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10
</code></pre>
下面我們看一張圖,讓我們更容易理解:

alt animation
alt animation
  • 方法五,轉場動畫

<pre><code>/**

  • 轉場動畫
  • @param fromView 當前View
  • @param toView 要顯示的View
  • @param duration 動畫持續時間
  • @param option 動畫類型
  • @param animations 動畫執行代碼
  • @param completion 動畫結束后,會自動調用這個block
    */
  • (void)transitionFromView:(UIView *)fromView
    toView:(UIView *)toView
    duration:(NSTimeInterval)duration
    options:(UIViewAnimationOptions)options
    completion:(void (^)(BOOL finished))completion;
    </code></pre>

小結:

  • 如果只是修改控件的屬性,使用首尾式動畫還是比較方便的,但是如果需要在動畫完成后做后續處理,就不是那么方便了。
  • 在實際的開發中更常用的時block代碼塊來處理動畫操作,塊動畫相對來說比較靈活,尤為重要的是能夠將動畫相關的代碼編寫在一起,便于代碼的閱讀和理解。

詳情見UIViewAnimations Demo

補充

1.UIImageView的幀動畫

UIImageView可以讓一系列的圖片在特定的時間內按順序顯示

相關屬性解析:

animationImages:要顯示的圖片(一個裝著UIImage的NSArray)

animationDuration:完整地顯示一次animationImages中的所有圖片所需的時間

animationRepeatCount:動畫的執行次數(默認為0,代表無限循環)

相關方法解析:

- (void)startAnimating; 開始動畫

- (void)stopAnimating;  停止動畫

- (BOOL)isAnimating;  是否正在運行動畫

</code></prep>

  • 這種方法在某些場景下是可以達到逐幀的動畫效果,但是它也存在著很大的性能問題,并且這種方法一旦設置完圖片中間的過程就無法控制了。

2.UIActivityIndicatorView

是一個旋轉進度輪,可以用來告知用戶有一個操作正在進行中,一般用initWithActivityIndicatorStyle初始化

UIActivityIndicatorViewStyle有3個值可供選擇:

UIActivityIndicatorViewStyleWhiteLarge   //大型白色指示器    

UIActivityIndicatorViewStyleWhite        //標準尺寸白色指示器    

UIActivityIndicatorViewStyleGray         //灰色指示器,用于白色背景

方法解析:

- (void)startAnimating; 開始動畫

- (void)stopAnimating;  停止動畫

- (BOOL)isAnimating;  是否正在運行動畫

3.UIDynamic

一、簡單介紹
1.什么是UIDynamic
  • UIDynamic是從iOS 7開始引入的一種新技術,隸屬于UIKit框架

  • 可以認為是一種物理引擎,能模擬和仿真現實生活中的物理現象。如:重力、彈性碰撞等現象

2.物理引擎的價值
  • 廣泛用于游戲開發,經典成功案例是“憤怒的小鳥”

  • 讓開發人員可以在遠離物理學公式的情況下,實現炫酷的物理仿真效果

  • 提高了游戲開發效率,產生更多優秀好玩的物理仿真游戲

3.知名的2D物理引擎
  • Box2d

  • Chipmunk

二、使用步驟

要想使用UIDynamic來實現物理仿真效果,大致的步驟如下

  1. 創建一個物理仿真器(順便設置仿真范圍)

  2. 創建相應的物理仿真行為(順便添加物理仿真元素)

  3. 將物理仿真行為添加到物理仿真器中,開始仿真

三、相關說明
1.三個概念

(1)誰要進行物理仿真?

物理仿真元素(Dynamic Item

(2)執行怎樣的物理仿真效果?怎樣的動畫效果?

物理仿真行為(Dynamic Behavior

(3)讓物理仿真元素執行具體的物理仿真行為

物理仿真器(Dynamic Animator

2.物理仿真元素

注意:

  • 不是任何對象都能做物理仿真元素
  • 不是任何對象都能進行物理仿真

物理仿真元素要素:

  • 任何遵守了UIDynamicItem協議的對象

  • UIView默認已經遵守了UIDynamicItem協議,因此任何UI控件都能做物理仿真

  • UICollectionViewLayoutAttributes類默認也遵守UIDynamicItem協議

3.物理仿真行為

(1)UIDynamic提供了以下幾種物理仿真行為

  • UIGravityBehavior:重力行為

  • UICollisionBehavior:碰撞行為

  • UISnapBehavior:捕捉行為

  • UIPushBehavior:推動行為

  • UIAttachmentBehavior:附著行為

  • UIDynamicItemBehavior:動力元素行為

(2)物理仿真行為須知

  • 上述所有物理仿真行為都繼承自UIDynamicBehavior

  • 所有的UIDynamicBehavior都可以獨立進行

  • 組合使用多種行為時,可以實現一些比較復雜的效果

4. 物理仿真器

(1)物理仿真器須知

  • 它可以讓物理仿真元素執行物理仿真行為

  • 它是UIDynamicAnimator類型的對象

(2)UIDynamicAnimator的初始化

  • - (instancetype)initWithReferenceView:(UIView *)view;

    view參數:是一個參照視圖,表示物理仿真的范圍

5.物理仿真器的說明

(1)UIDynamicAnimator的常見方法

- (void)addBehavior:(UIDynamicBehavior *)behavior;//添加1個物理仿真行為

- (void)removeBehavior:(UIDynamicBehavior *)behavior;//移除1個物理仿真行為

- (void)removeAllBehaviors;//移除之前添加過的所有物理仿真行為

(2)UIDynamicAnimator的常見屬性

@property (nonatomic, readonly) UIView* referenceView; //參照視圖

@property (nonatomic, readonly, copy) NSArray* behaviors;//添加到物理仿真器中的所有物理仿真行為

@property (nonatomic, readonly, getter = isRunning) BOOL running;//是否正在進行物理仿真

@property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;//代理對象(能監聽物理仿真器的仿真過程,比如開始和結束)

詳情見DynamicAnimationDemo

================

二、Core Animation

什么是Animation(動畫),簡單點說就是在一段時間內,顯示的內容發生了變化.對CALayer來說就是在一段時間內,其Animatable Property發生了變化.
這里涉及到兩個東西: 一是Layer(基類CALayer),一是Animation(基于CAAnimation). Animation作用于Layer.CALayer提供了接口用于給自己添加Animation.

Core Animation是一組非常強大的動畫處理API,使用它能做出非常絢麗的動畫效果,而且往往是事半功倍,使用它需要添加QuartzCore .framework和引入對應的框架<QuartzCore/QuartzCore.h> .

開發步驟:

1> 初始化一個動畫對象(CAAnimation)并設置一些動畫相關屬性.

2> 添加動畫對象到層(CALayer)中,開始執行動畫.

Core Animation的動畫執行過程都是在后臺操作的,不會阻塞主線程.

1. CALayer

CALayer與UIView的關系

在iOS中,你能看得見摸得著的東西基本上都是UIView,比如一個按鈕、一個文本標簽、一個文本輸入框、一個圖標等等,這些都是UIView。

其實UIView之所以能顯示在屏幕上,完全是因為它內部的一個圖層:

  • 在創建UIView對象時,UIView內部會自動創建一個圖層(即CALayer對象),通過UIView的layer屬性可以訪問這個層。

    @property(nonatomic,readonly,strong) CALayer *layer;

當UIView需要顯示到屏幕上時,會調用drawRect:方法進行繪圖,并且會將所有內容繪制在自己的圖層上,繪圖完畢后,系統會將圖層拷貝到屏幕上,于是就完成了UIView的顯示。

換句話說,UIView本身不具備顯示的功能,是它內部的層才有顯示功能。

因此,通過調節CALayer對象,可以很方便的調整UIView的一些外觀屬性。

  • 對比CALayer,UIView多了一個事件處理的功能。也就是說,CALayer不能處理用戶的觸摸事件,而UIView可以。所以,如果顯示出來的東西需要跟用戶進行交互的話,用UIView;如果不需要跟用戶進行交互,用UIView或者CALayer都可以。當然,CALayer的性能會高一些,因為它少了事件處理的功能,更加輕量級。

Layer的渲染架構

Layer也和View一樣存在著一個層級樹狀結構,稱之為圖層樹(Layer Tree),直接創建的或者通過UIView獲得的(view.layer)用于顯示的圖層樹,稱之為模型樹(Model Tree),模型樹的背后還存在兩份圖層樹的拷貝,一個是呈現樹(Presentation Tree),一個是渲染樹(Render Tree)。

呈現樹可以通過普通layer(其實就是模型樹)的layer.presentationLayer獲得,而模型樹則可以通過modelLayer屬性獲得。

  • 模型樹的屬性在其被修改的時候就變成了新的值,這個是可以用代碼直接操控的部分;
  • 呈現樹的屬性值和動畫運行過程中界面上看到的是一致的;
  • 渲染樹是私有的,你無法訪問到,渲染樹是對呈現樹的數據進行渲染。

為了不阻塞主線程,渲染的過程是在單獨的進程或線程中進行的,所以你會發現Animation的動畫并不會阻塞主線程.

隱式動畫

根層與非根層:

每一個UIView內部都默認關聯著一個CALayer,我們可用稱這個Layer為Root Layer(根層)

所有的非Root Layer,也就是手動創建的CALayer對象,都存在著隱式動畫

當對非Root Layer的部分屬性進行修改時,默認會自動產生一些動畫效果,而這些屬性稱為Animatable Properties(可動畫屬性)。

可以通過事務關閉隱式動畫:
CATransaction 是核心動畫里面負責協調多個動畫原子更新顯示操作。事務支持嵌套使用。
<pre><code>[CATransaction begin];
// 關閉隱式動畫
[CATransaction setDisableActions:YES];

self.myview.layer.position = CGPointMake(10, 10);

[CATransaction commit];</code></pre>

CALayer的基本屬性

<pre><code>position和anchorPoint的作用
@property CGPoint position;

用來設置CALayer在父層中的位置
以父層的左上角為原點(0, 0)

@property CGPoint anchorPoint;

稱為“定位點”、“錨點”,
決定著CALayer身上的哪個點會在position屬性所指的位置。
以自己的左上角為原點(0, 0),
它的x、y取值范圍都是0~1,默認值為中心點(0.5, 0.5)

anchorPoint和position的關系舉例:

假如錨點anchorPoint為默認值即中點(0.5,0.5),而該層的position設置為(0,0)即為父層的左上點,那么該層在父層中只會看到四分之一的部分。
</code></pre>
為了進一步說明anchorPoint的作用,假設有一個層大小100*100,現在中心點位置(50,50),由此可以得出frame(0,0,100,100)。上面說過anchorPoint默認為(0.5,0.5),同中心點position重合,此時使用圖形描述如圖1;當修改anchorPoint為(0,0),此時錨點處于圖層左上角,但是中心點poition并不會改變,因此圖層會向右下角移動,如圖2;然后修改anchorPoint為(1,1,),position還是保持位置不變,錨點處于圖層右下角,此時圖層如圖3。


2.CAAnimation概述

當需要對非Root Layer進行動畫或者需要對動畫做更多自定義的行為的時候,就必須使用到顯式動畫了,顯式動畫的基類為CAAnimation,顯式動畫不會改變該屬性的值,它只是用于動畫顯示。

  • 采用了CAMediaTiming協議:可以調整時間,包括持續時間,速度,重復次數,并且能設定圖層過渡;
  • 采用了CAAction協議:可以通過響應動作的方式來顯示動畫.

來看下CAAnimation的繼承體系

  • CAAnimation是個抽象類,不具備動畫效果,必須用它的子類才有動畫效果。

  • CAPropertyAnimation也是個抽象類,本身不具備動畫效果,只有子類才有。

    CABasicAnimation和CAKeyframeAnimation:

CABasicAnimation基本動畫,做一些簡單效果。
CAKeyframeAnimation關鍵幀動畫,做一些連續的流暢的動畫。
  • CAAnimationGroup是個動畫組,可以同時進行縮放,旋轉(同時進行多個動畫)。
  • CATransition是轉場動畫,界面之間跳轉(切換)都可以用轉場動畫。
1)CAAnimation——簡介

是所有動畫對象的父類,負責控制動畫的持續時間和速度,是個抽象類,不能直接使用,應該使用它具體的子類。

基本屬性說明:
  • duration:動畫的持續時間

  • repeatCount:重復次數,無限循環可以設置HUGE_VALF或者MAXFLOAT

  • repeatDuration: 重復時間

  • removedOnCompletion:默認為YES,代表動畫執行完畢后就從圖層上移除,圖形會恢復到動畫執行前的狀態。如果想讓圖層保持顯示動畫執行后的狀態,那就設置為NO,不過還要設置fillMode為kCAFillModeForwards

  • fillMode: 決定當前對象在非active時間段的行為。比如動畫開始之前或者動畫結束之

    fillMode屬性的設置:

       kCAFillModeRemoved 這個是默認值,也就是說當動畫開始前和動畫結束后,動畫對layer都沒有影響,動畫結束后,layer會恢復到之前的狀態
    
       kCAFillModeForwards 當動畫結束后,layer會一直保持著動畫最后的狀態
    
       kCAFillModeBackwards 在動畫開始前,只需要將動畫加入了一個layer,layer便立即進入動畫的初始狀態并等待動畫開始。
    
       kCAFillModeBoth 這個其實就是上面兩個的合成.動畫加入后開始之前,layer便處于動畫初始狀態,動畫結束后layer保持動畫最后的狀態
    
  • beginTime: 可以用來設置動畫延遲執行時間,若想延遲2s,就設置為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當前時間

  • timingFunction: 速度控制函數,控制動畫運行的節奏

    速度控制函數(CAMediaTimingFunction):

       kCAMediaTimingFunctionLinear(線性):勻速,給你一個相對靜態的感覺
    
       kCAMediaTimingFunctionEaseIn(漸進):動畫緩慢進入,然后加速離開
    
       kCAMediaTimingFunctionEaseOut(漸出):動畫全速進入,然后減速的到達目的地
    
       kCAMediaTimingFunctionEaseInEaseOut(漸進漸出):動畫緩慢的進入,中間加速,然后減速的到達目的地。這個是默認的動畫行為>
    
  • delegate:動畫代理

CAAnimation在分類中定義了代理方法

<pre><code>
@interface NSObject (CAAnimationDelegate)

/* Called when the animation begins its active duration. */
// 動畫開始時調用

  • (void)animationDidStart:(CAAnimation *)anim;

/* Called when the animation either completes its active duration or

  • is removed from the object it is attached to (i.e. the layer). 'flag'
  • is true if the animation reached the end of its active duration
  • without being removed. */
    // 動畫結束后調用
  • (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

@end</code></pre>

2)CAPropertyAnimation

是CAAnimation的子類,也是個抽象類,要想創建動畫對象,應該使用它的兩個子類:CABasicAnimationCAKeyframeAnimation。

基本屬性說明:
keyPath:    通過指定CALayer的一個屬性名稱為keyPath(NSString類型),并且對CALayer的這個屬性的值進行修改,達到相應的動畫效果。比如,指定@“position”為keyPath,就修改CALayer的position屬性的值,以達到平移的動畫效果
CABasicAnimation——基本動畫

屬性說明:

fromValue:  keyPath相應屬性的初始值
toValue:    keyPath相應屬性的結束值
byValue:    keyPath相應屬性的改變值

動畫過程說明:

隨著動畫的進行,在長度為duration的持續時間內,keyPath相應屬性的值從fromValue漸漸地變為toValue。

keyPath內容是CALayer的可動畫Animatable屬性。

如果fillMode = kCAFillModeForwards同時removedOnComletion = NO,那么在動畫執行完畢后,圖層會保持顯示動畫執行后的狀態。但在實質上,圖層的屬性值還是動畫執行前的初始值,并沒有真正被改變。

CAKeyframeAnimation——關鍵幀動畫

關鍵幀動畫,也是CAPropertyAnimation的子類,與CABasicAnimation的區別是:

CABasicAnimation只能從一個數值(fromValue)變到另一個數值(toValue),而CAKeyframeAnimation會使用一個NSArray保存這些數值

CABasicAnimation可看做是只有2個關鍵幀的CAKeyframeAnimation

屬性說明:

values: NSArray對象。里面的元素稱為“關鍵幀”(keyframe)。動畫對象會在指定的時間(duration)內,依次顯示values數組中的每一個關鍵幀

path: 可以設置一個CGPathRef、CGMutablePathRef,讓圖層按照路徑軌跡移動。path只對CALayer的anchorPoint和position起作用。如果設置了path,那么values將被忽略

keyTimes: 可以為對應的關鍵幀指定對應的時間點,其取值范圍為0到1.0,keyTimes中的每一個時間值都對應values中的每一幀。如果沒有設置keyTimes,各個關鍵幀的時間是平分的

3)CAAnimationGroup——動畫組

動畫組,是CAAnimation的子類,可以保存一組動畫對象,將CAAnimationGroup對象加入層后,組中所有動畫對象可以同時并發運行。

默認情況下,一組動畫對象是同時運行的,也可以通過設置動畫對象的beginTime屬性來更改動畫的開始時間。

屬性說明:

animations: 用來保存一組動畫對象的NSArray

4)CATransition——轉場動畫

CATransition是CAAnimation的子類,用于做轉場動畫,能夠為層提供移出屏幕和移入屏幕的動畫效果。iOS比Mac OS X的轉場動畫效果少一點。

UINavigationController就是通過CATransition實現了將控制器的視圖推入屏幕的動畫效果。

屬性說明:

type: 動畫過渡類型

subtype: 動畫過度方向

subtype

startProgress: 動畫起點(在整體動畫的百分比)

endProgress: 動畫終點(在整體動畫的百分比)

步驟

1.創建轉場動畫

2.設置轉場類型、子類型(可選)及其他屬性

3.設置轉場后的新視圖并添加動畫到圖層

舉例
<pre><code>CATransition *anim = [CATransition animation];
anim.type = @"cube";
anim.subtype = kCATransitionFromBottom;
[view.layer addAnimation:anim forKey:nil];
</code></pre>

詳情見KKCoreAnimation&&SKBounceAnimation

3.補充

1)CASpringAnimation

iOS9才引入的動畫類,它繼承于CABaseAnimation,用于制作彈簧動畫

參數說明

mass://質量,影響圖層運動時的彈簧慣性,質量越大,彈簧拉伸和壓縮的幅度越大,動畫的速度變慢,并且波動幅度變大

stiffness://剛度系數(勁度系數/彈性系數),剛度系數越大,形變產生的力就越大,運動越快

damping://阻尼系數,阻止彈簧伸縮的系數,阻尼系數越大,停止越快

initialVelocity://初始速率,動畫視圖的初始速度大小
速率為正數時,速度方向與運動方向一致,速率為負數時,速度方向與運動方向相反

settlingDuration://結算時間 返回彈簧動畫到停止時的估算時間,根據當前的動畫參數估算
通常彈簧動畫的時間使用結算時間比較準確

2)CAShapeLayer:

CAShapeLayer顧名思義,繼承于CALayer。 每個CAShapeLayer對象都代表著將要被渲染到屏幕上的一個任意的形狀(shape)。具體的形狀由其path(類型為CGPathRef)屬性指定。 普通的CALayer是矩形,所以需要frame屬性。CAShapeLayer初始化時也需要指定frame值,但 它本身沒有形狀,它的形狀來源于其屬性path 。CAShapeLayer有不同于CALayer的屬性,它從CALayer繼承而來的屬性在繪制時是不起作用的。

3)CADisplayLink

CADisplayLink是一個計時器,但是同NSTimer不同的是,CADisplayLink的刷新周期同屏幕完全一致。例如在iOS中屏幕刷新周期是60次/秒,CADisplayLink刷新周期同屏幕刷新一致也是60次/秒,這樣一來使用它完成的逐幀動畫(又稱為“時鐘動畫”)完全感覺不到動畫的停滯情況。

iOS程序在運行后就進入一個消息循環中(這個消息循環稱為“主運行循環”),整個程序相當于進入一個死循環中,始終等待用戶輸入。將CADisplayLink加入到主運行循環隊列后,它的時鐘周期就和主運行循環保持一致,而主運行循環周期就是屏幕刷新周期。在CADisplayLink加入到主運行循環隊列后就會循環調用目標方法,在這個方法中更新視圖內容就可以完成逐幀動畫。

使用方法:
<pre><code>定義CADisplayLink并制定觸發調用方法
將顯示鏈接添加到主運行循環隊列
// 定義
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotationChange)];
// 添加到主循環隊列
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
開始和暫停
// 暫停
link.paused = YES;
// 開始
link.paused = NO;
</code></pre>

三、FaceBook POP動畫

1.工作機制

POP是一個在iOS與OS X上通用的極具擴展性的動畫引擎 它在基本的靜態動畫的基礎上增加的彈簧動畫與衰減動畫。

使之能創造出更真實更具物理性的交互動畫 POP的API可以快速的與現有的ObjC代碼集成并可以作用于任意對象的任意屬性。

POP 本質上是基于定時器的動畫庫,使用每秒 60 頻率的定時器,即時鐘頻率為 1/60 秒(為了匹配 iOS 顯示屏幀率),使得動畫刷新繪制頻率與屏幕刷新頻率一致。很多這類動畫庫都使用 CADisplayLink 做為一個回調源。

在計算機的世界里面,其實并不存在絕對連續的動畫,你所看到的屏幕上的動畫本質上都是離散的,只是在一秒的時間里面離散的幀多到一定的數量人眼就覺得是連續的了,在iOS中,最大的幀率是60幀每秒。 iOS提供了Core Animation框架,只需要開發者提供關鍵幀信息,比如提供某個animatable屬性終點的關鍵幀信息,然后中間的值則通過一定的算法進行插值計算,從而實現補間動畫。 Core Aniamtion中進行插值計算所依賴的時間曲線由CAMediaTimingFunction提供。 Pop Animation在使用上和Core Animation很相似,都涉及Animation對象以及Animation的載體的概念,不同的是Core Animation的載體只能是CALayer,而Pop Animation可以是任意基于NSObject的對象。當然大多數情況Animation都是界面上顯示的可視的效果,所以動畫執行的載體一般都直接或者間接是UIView或者CALayer。

  • Pop Animation相比于Core Animation的優點

      1. Pop Animation應用于CALayer時,在動畫運行的任何時刻,layer和其presentationLayer的相關屬性值始終保持一致,而Core Animation做不到。 
      2.Pop Animation可以應用任何NSObject的對象,而Core Aniamtion必須是CALayer。
    

2.源碼結構:

代碼包括四個目錄:

Animations: 定義pop支持的動畫類型,并抽像各種動畫的低層數據結構

Engine:組織動化運行的數據結構,核心是動化管理者,還包括了動畫引擎所需要的可動畫屬性定義、動畫追蹤等內容

Utility: 封裝Engine中用到的各種功能,包括數值運算,數據轉換,運算等

WebCore: 這部分是蘋果公司的代碼,矩陣運算和貝賽爾曲線的,用于底層運算。

1)Animations

 POPAnimation :定義了動畫基類POPAnimation
    私有變量:結構體`_POPAnimationState` 紀錄動畫狀態,是實現動畫最關鍵的屬性
    公有變量:name beginTime delegate tracer(動畫追蹤,紀錄各種動畫事件) ^completionBlock removedOnCompletion paused
繼承關系:
    
NSObject
 POPAnimation
     POPPropertyAnimation
          POPBasicAnimation
          POPDecayAnimation
          POPSpringAnimation
     POPCustomAnimation

 _POPAnimationState
    _POPPropertyAnimationState
        _POPBasicAnimationState
        _POPDecayAnimationState
        _POPSpringAnimationState

NSObject (POP)讓所有對象增加pop動畫支持(增刪改查)通過POPAnimator進行管理

2)Engine

POPAnimateableProperty 可動畫的屬性,用于定義動畫類型和動畫時修改值
    POPStaticAnimatablePropertyState 結構體紀錄了屬性名,readBlock,writeBlock,和域值

    POPStaticAnimatablePropertyState _staticStates[]  紀錄了所有可動畫的屬性對應的名稱,其中的writeblock功能是把二進制數據寫到對應的屬性里

類族:

POPAnimatableProperty
    POPConcreteAnimatableProperty
    POPMutableAnimatableProperty
    POPPlaceholderAnimatableProperty
    POPStaticAnimatableProperty
    
POPAnimationEvent POPAnimationTracer的基本元素

POPAnimationExtras 擴展CAAnimation 和POPSpringAnimation 的方法(分類)

POPAnimationRuntime 這里有幾個函數比較特殊
    POPBox 包裝一個函數vector,把vector轉化為point,size,rect,color等
    POPUnbox 解包一個向量,把point,size,rect,color對象轉換為vector

POPAnimationTracer 動畫跟蹤 通過POPAnimationEvent來描述

POPAnimator 動畫管理者,紀錄所有的動畫事件(POPAnimatorItem,紀錄了動畫作用到的對象、動畫key、動畫對象等信息),初始化是把CADisplayLink注冊到runloop里定時觸發render過程,進行一幀動畫渲染。她提供了add、remove等操作Animation集合的方法,并提供了Observer和delegate等事件函數
POPAnimator通過兩層(key,view)存儲動畫,(動畫目標對象,(動畫key,動畫對象))
具體每幀的渲染過程有兩步:1.renderTime,更新state的狀態。 2.updateAnimatable,把state的變化更新到obj的具體屬性上

3)Utility 各種工具類

POPAction: ActionDisabler和ActionEnabler  利用RAII暫停核心動畫以ActionEnabler為例,創建ActionEnabler時停止動畫,銷毀時重新運行動畫

POPCGUtils:顏色轉換函數,數組和點,point,size,rect,color等轉換函數

POPGeometry:擴展NSValue到POP自定義類型的轉換

POPLayerExtras:圖層矩陣變換封裝,底層由TransformationMatrix實現

POPMath:數學計算接口,封裝了UnitBezier,POPVector和其他數字計算

SpringSolver:spring插值計算

POPVector:向量運算

4)WebCore

FloatConversion:浮點數轉換方法,提供double->float和double->CGFloat,
用途:服務于矩陣運算

TransformationMatrix:矩陣運算,包括初始化,scale,rotate,translate,flipX,flipY,skew,applyPerspective???,multVecMatrix向量和矩陣相乘等矩陣操作,
CATransform3D 矩陣變換之立方體旋轉實現細節 
關鍵方法說明:
計算行列式的值:不列舉了,很枯燥,行列式計算的基本概念,從二階計算到三階再計算到四階。主要作用是引擎層對layer進行坐標變換

UnitBezier: 結構體,初始化參數為兩個控制點p1(p1x,p1y),p2(p2x,p2y),用于表示起始點為s(0,0),終止點為e(1,1),p1為第一控制點,p2為第二控制點的二次Bezier。
用途:重新實現系統的自帶動畫
方法說明:
UnitBezier(double p1x, double p1y, double p2x, double p2y)//用兩個控制點的坐標初始化曲線,
double sampleCurveX(double t)//通過參數t計算對應的x值
double sampleCurveY(double t)//通過參數t計算對應的y值
double sampleCurveDerivativeX(double t)
//epsilon表示一個小間距,相當于數學計算里的dX,一般為全距離的1/1000,
//求解x對應的t值,用到了函數sampleCurveDerivativeX
double solveCurveX(double x, double epsilon)
double solve(double x, double epsilon)//求解x對應的y值,分為兩步算,1.由x計算t;2.由t計算y

3.動畫執行流程:

1)POPAnimator是單例對象,初始化對象實例時注冊把CADisplayLink到runloop,定時調用render,通過renderTime函數遍歷所有正在執行的動畫,使動畫進行到下一幀,并刷新畫面,直到所有動畫推進完成。

2)動畫狀態的推進最終都是通過_POPAnimationState類和其子類的advance方法推進的,advance更新時間戳,updateAnimatable方法把state的狀態變更到動畫要作用的obj對象。

3)Spring、Decay、Basic 都有各自實現的advance函數計算,而Custom方式不同,他是通過一個POPCustomAnimationBlock類型的回調來就算這一幀的值的。

4.動畫使用

1)POPBasicAnimation

基本動畫,接口方面和CABasicAniamtion很相似,使用可以提供初始值fromValue,這個 終點值toValue,動畫時長duration以及決定動畫節奏的timingFunction。timingFunction直接使用的CAMediaTimingFunction,是使用一個橫向縱向都為一個單位的擁有兩個控制點的貝賽爾曲線來描述的,橫坐標為時間,縱坐標為動畫進度。

NSInteger height = CGRectGetHeight(self.view.bounds); 
NSInteger width = CGRectGetWidth(self.view.bounds); 

CGFloat centerX = arc4random() % width; 
CGFloat centerY = arc4random() % height; 

POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter]; 
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerY)]; 
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
anim.duration = 0.4; 
[self.testView pop_addAnimation:anim forKey:@"centerAnimation"]; 
2)PopSpringAnimation

彈簧動畫是Bezier曲線無法表述的,所以無法使用PopBasicAniamtion來實現。PopSpringAnimation便是專門用來實現彈簧動畫的。

POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter]; 

NSInteger height = CGRectGetHeight(self.view.bounds); 

NSInteger width = CGRectGetWidth(self.view.bounds); 

CGFloat centerX = arc4random() % width; 

CGFloat centerY = arc4random() % height; 

anim.toValue = [NSValue valueWithCGPoint:CGPointMake(centerX, centerY)]; 

anim.springBounciness = 16; 

anim.springSpeed = 6; 

[self.testView pop_addAnimation:anim forKey:@"center"]; 

屬性介紹

  • springBounciness 彈簧彈力 取值范圍為[0, 20],默認值為4

  • springSpeed 彈簧速度,速度越快,動畫時間越短 [0, 20],默認為12,和springBounciness一起決定著彈簧動畫的效果

  • dynamicsTension 彈簧的張力

  • dynamicsFriction 彈簧摩擦

  • dynamicsMass 質量 。張力,摩擦,質量這三者可以從更細的粒度上替代springBounciness和springSpeed控制彈簧動畫的效果

3)PopDecayAnimation

基于Bezier曲線的timingFuntion同樣無法表述Decay Aniamtion,所以Pop就單獨實現了一個 PopDecayAnimation,用于衰減動畫。衰減動畫一個很常見的地方就是 UIScrollView 滑動松開后的減速,這里就基于UIView實現一個自己的ScrollView,然后使用PopDecayAnimation實現 此代碼可以詳細參見 KKScrollView 的實現,當滑動手勢結束時,根據結束的加速度,給衰減動畫一個初始的velocity,用來決定衰減的時長。

4)POPCustomAnimation

通過自定義block刷新動畫幀,更靈活的方式

POPCustomAnimation 并不是基于POPPropertyAnimation的,它直接繼承自PopAnimation用于創建自定義動畫用的,通過POPCustomAnimationBlock類型的block進行初始化,

typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation); 

此block會在界面的每一幀更新的時候被調用,創建者需要在block中根據當前currentTime和elapsedTime來決定如何更新target的相關屬性,以實現特定的動畫。當你需要結束動畫的時候就在block中返回NO,否則返回YES。

詳情見facebook-pop-sample&&POP-Handapp

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,566評論 6 30
  • 學習及實踐筆記 記錄iOS動畫的學習及實踐 目錄 顯示層(UIView)動畫初級動畫關鍵幀動畫逐幀動畫Gif動畫的...
    Tr2e閱讀 2,653評論 8 45
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,141評論 5 13
  • 先看看CAAnimation動畫的繼承結構 CAAnimation{ CAPropertyAnimation { ...
    時間不會倒著走閱讀 1,689評論 0 1
  • 一、CoreAnimation(核心動畫) 1.什么是核心動畫 Core Animation可以用在 Mac OS...
    就叫yang閱讀 9,217評論 1 34