目錄
- ** UIView 動(dòng)畫(huà) **
- ** Core Animation **
- ** FaceBook POP動(dòng)畫(huà) **
在iOS中,圖形可分為以下幾個(gè)層次:
<p>OpenGL ES使用硬件加速接口來(lái)處理先進(jìn)的2d 和3d 呈現(xiàn)。OpenGLES通常由游戲開(kāi)發(fā)者或想實(shí)現(xiàn)沉浸式圖像體驗(yàn)的開(kāi)發(fā)者使用。OpenGLES框架提供對(duì)呈現(xiàn)過(guò)程的全部控制,以及提供創(chuàng)建平滑動(dòng)畫(huà)所需要的幀速。</p>
- 創(chuàng)建2D和3D圖形
- 創(chuàng)建更復(fù)雜的圖形,比如數(shù)據(jù)虛擬化、模擬飛行,或者視頻游戲
- 訪問(wèn)底層圖形設(shè)備
<p>Core Graphics也稱作Quartz,是對(duì)定制的2D向量和圖像呈現(xiàn)提供支持的本地繪制引擎。該框架提供的引擎雖然沒(méi)有OpenGLES引擎速度快,但該框架能夠很好地適合于呈現(xiàn)定制的2d圖形和動(dòng)態(tài)圖像。</p>
- 創(chuàng)建基于路徑的繪圖
- 抗鋸齒渲染
- 添加梯度、圖片和顏色
- Use coordinate-space transformations.
- 創(chuàng)建、顯示和分析PDF文檔
<p>Core Animation也是Quartz核心框架的一部分,是優(yōu)化應(yīng)用動(dòng)畫(huà)體驗(yàn)的基礎(chǔ)技術(shù)。使用Core Animation可以創(chuàng)建嵌套的對(duì)象,并且可以對(duì)它們操作、旋轉(zhuǎn)、縮放和轉(zhuǎn)換。使用Core animation,你可以創(chuàng)建動(dòng)態(tài)的用戶界面而不用使用更底層的圖形API,如OpenGL ES。</p>
- 創(chuàng)建定制動(dòng)畫(huà)
- 添加定時(shí)函數(shù)和圖形
- 支持幀動(dòng)畫(huà)
- Specify graphical layout constraints.
- Group multiple-layer changes into anatomic update.
<p>UIKit視圖基于 Core Animation提供視圖級(jí)別的動(dòng)畫(huà)支持。</p>
實(shí)現(xiàn)動(dòng)畫(huà)三要素
- 元素(who)
- 行為(how)
- 執(zhí)行(do)
兩個(gè)概念
1.仿射變換(Affine Transformation或 Affine Map)
是一種二維坐標(biāo)到二維坐標(biāo)之間的線性變換,它保持了二維圖形的“平直性”(即:直線經(jīng)過(guò)變換之后依然是直線)和“平行性”(即:二維圖形之間的相對(duì)位置關(guān)系保持不變,平行線依然是平行線,且直線上點(diǎn)的位置順序不變)。
- 變換原理
<pre><code>struct CGAffineTransform {
CGFloat a;
CGFloat b;
CGFloat c;
CGFloat d;
CGFloat tx;
CGFloat ty;
};</code></pre>
結(jié)構(gòu)體矩陣圖為:(矩陣圖)
因?yàn)樽詈笠涣锌偸鞘?0,0,1),所以有用的信息就是前面兩列
對(duì)一個(gè)view進(jìn)行仿射變化就相當(dāng)于對(duì)view上的每個(gè)點(diǎn)做一個(gè)乘法
結(jié)果就是:(映射變換)
相當(dāng)于:
(x, y, 1 ) --> (ax + cy + tx, bx + dy + ty, 1)
如果不看c和b的話
a表示x水平方向的縮放,tx表示x水平方向的偏移
d表示y垂直方向的縮放,ty表示y垂直方向的偏移
如果b和c不為零的話,那么視圖肯定發(fā)生了旋轉(zhuǎn)
<p>仿射變換可以通過(guò)一系列的原子變換的復(fù)合來(lái)實(shí)現(xiàn),包括:平移(Translation)、縮放(Scale)、翻轉(zhuǎn)(Flip)、旋轉(zhuǎn)(Rotation)和錯(cuò)切(Shear)。
</p>
- 常用函數(shù)
<pre><code>/// 用來(lái)連接兩個(gè)變換效果并返回。返回的t = t1 * t2
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2)
/// 矩陣初始值。[ 1 0 0 1 0 0 ]
CGAffineTransformIdentity
/// 自定義矩陣變換,需要掌握矩陣變換的知識(shí)才知道怎么用。參照(x, y, 1 ) --> (ax + cy + tx, bx + dy + ty, 1)
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)
/// 旋轉(zhuǎn)視圖。傳入?yún)?shù)為 角度 * (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.貝塞爾曲線
是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。
曲線定義:起始點(diǎn)、終止點(diǎn)(也稱錨點(diǎn))、控制點(diǎn)。
通過(guò)調(diào)整控制點(diǎn),貝塞爾曲線的形狀會(huì)發(fā)生變化。
- 線性貝塞爾曲線

由 P0 至 P1 的連續(xù)點(diǎn), 描述的一條線段
- 二次貝塞爾曲線

原理:
由 P0 至 P1 的連續(xù)點(diǎn) Q0,描述一條線段
由 P1 至 P2 的連續(xù)點(diǎn) Q1,描述一條線段。
由 Q0 至 Q1 的連續(xù)點(diǎn) B(t),描述一條二次貝塞爾曲線。
- 三次貝塞爾曲線

** 通用公式:**
** 高階貝塞爾曲線:**
- 四次貝塞爾曲線

- 五次貝塞爾曲線
貝塞爾曲線應(yīng)用在動(dòng)畫(huà)中,描述物件的運(yùn)動(dòng)路徑等等。
UIBezierPath
使用UIBezierPath類可以創(chuàng)建基于矢量的路徑,這個(gè)類在UIKit中。此類是Core Graphics框架關(guān)于CGPathRef的一個(gè)封裝。
path如果是基于矢量形狀的,都用直線和曲線段去創(chuàng)建。 我們使用直線段去創(chuàng)建矩形和多邊形,使用曲線段去創(chuàng)建弧(arc),圓或者其他復(fù)雜的曲線形狀。 每一段都包括一個(gè)或者多個(gè)點(diǎn),繪圖命令定義如何去詮釋這些點(diǎn)。每一個(gè)直線段或者曲線段的結(jié)束的地方是下一個(gè)的開(kāi)始的地方。每一個(gè)連接的直線或者曲線段的集合成為subpath。一個(gè)UIBezierPath對(duì)象定義一個(gè)完整的路徑包括一個(gè)或者多個(gè)subpaths。
使用UIBezierPath畫(huà)圖步驟:
- 1.創(chuàng)建一個(gè)UIBezierPath對(duì)象
- 2.調(diào)用-moveToPoint:設(shè)置初始線段的起點(diǎn)
- 3.添加線或者曲線去定義一個(gè)或者多個(gè)子路徑
- 4.改變UIBezierPath對(duì)象跟繪圖相關(guān)的屬性。如,我們可以設(shè)置畫(huà)筆的屬性、填充樣式等
詳情見(jiàn)
UIBezierPath_And_CAShapeLayer
===================
一、UIView 動(dòng)畫(huà)
** 可實(shí)現(xiàn)動(dòng)畫(huà)的屬性 **
<pre><code>坐標(biāo)尺寸類: bounds、frame、center
視圖顯示類: backgroundColor、alpha、hidden
形態(tài)變化類: transform</code></pre>
1、首尾式
** 基本寫(xiě)法,代碼必須放在Begin和Commit之間: **
<pre><code>[UIView beginAnimations:nil context:nil]; // 開(kāi)始動(dòng)畫(huà)
// Code...
[UIView commitAnimations]; // 提交動(dòng)畫(huà)</code></pre>
** 簡(jiǎn)單例子:**
<pre><code>[UIView beginAnimations:nil context:nil]; // 開(kāi)始動(dòng)畫(huà)
[UIView setAnimationDuration:10.0]; // 動(dòng)畫(huà)時(shí)長(zhǎng)
/**
- 圖像向下移動(dòng)
*/
CGPoint point = _imageView.center;
point.y += 150;
[_imageView setCenter:point];
[UIView commitAnimations]; // 提交動(dòng)畫(huà)</code></pre>
**同時(shí)運(yùn)行多個(gè)動(dòng)畫(huà)效果: **
<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>
以上代碼實(shí)現(xiàn)的動(dòng)畫(huà)效果為(同時(shí)執(zhí)行):
1、圖像向下平移150像像
2、設(shè)置圖像透明度為0。
其它方法及屬性:
以下方法及屬性不為全部,只例舉部分:
<pre><code>// 開(kāi)始動(dòng)畫(huà)
- (void)beginAnimations:(NSString *)animationID context:(void *)context;
// 提交動(dòng)畫(huà)
- (void)commitAnimations;
// 設(shè)置動(dòng)畫(huà)曲線,默認(rèn)是勻速進(jìn)行:
- (void)setAnimationCurve:(UIViewAnimationCurve)curve;
// 設(shè)置動(dòng)畫(huà)時(shí)長(zhǎng):
- (void)setAnimationDuration:(NSTimeInterval)duration;
// 默認(rèn)為YES。為NO時(shí)跳過(guò)動(dòng)畫(huà)效果,直接跳到執(zhí)行后的狀態(tài)。
- (void)setAnimationsEnabled:(BOOL)enabled;
// 設(shè)置動(dòng)畫(huà)延遲執(zhí)行(delay:秒為單位):
- (void)setAnimationDelay:(NSTimeInterval)delay;
// 動(dòng)畫(huà)的重復(fù)播放次數(shù)
- (void)setAnimationRepeatCount:(float)repeatCount;
// 如果為YES,逆向(相反)動(dòng)畫(huà)效果,結(jié)束后返回動(dòng)畫(huà)逆向前的狀態(tài); 默認(rèn)為NO:
- (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
// 設(shè)置動(dòng)畫(huà)代理:
- (void)setAnimationDelegate:(id)delegate;
// 動(dòng)畫(huà)將要開(kāi)始時(shí)執(zhí)行方法××(必須要先設(shè)置動(dòng)畫(huà)代理):
- (void)setAnimationWillStartSelector:(SEL)selector;
// 動(dòng)畫(huà)已結(jié)束時(shí)執(zhí)行方法××(必須要先設(shè)置動(dòng)畫(huà)代理):
- (void)setAnimationDidStopSelector:(SEL)selector;
/**
- 設(shè)置動(dòng)畫(huà)過(guò)渡效果
- @param transition 動(dòng)畫(huà)的過(guò)渡效果
- @param view 過(guò)渡效果作用視圖
- @param cache 如果為YES,開(kāi)始和結(jié)束視圖分別渲染一次并在動(dòng)畫(huà)中創(chuàng)建幀;否則,視圖將會(huì)渲染每一幀。例如,你不需要在視圖轉(zhuǎn)變中不停的更新,你只需要等到轉(zhuǎn)換完成再去更新視圖。
*/
- (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
轉(zhuǎn)場(chǎng)類型
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
</code></pre>
2、block:
方法一:
<pre><code>[UIView animateWithDuration:4.0 // 動(dòng)畫(huà)時(shí)長(zhǎng)
animations:^{
// code
}];</code></pre>方法二:
<pre><code>[UIView animateWithDuration:4.0 // 動(dòng)畫(huà)時(shí)長(zhǎng)
animations:^{
// code...
}
completion:^(BOOL finished) {
// 動(dòng)畫(huà)完成后執(zhí)行
// code...
}];</code></pre>
- 方法三:
<pre><code>[UIView animateWithDuration:4.0 // 動(dòng)畫(huà)時(shí)長(zhǎng)
delay:2.0 // 動(dòng)畫(huà)延遲
options:UIViewAnimationOptionCurveEaseIn // 動(dòng)畫(huà)過(guò)渡效果
animations:^{
// code...
}
completion:^(BOOL finished) {
// 動(dòng)畫(huà)完成后執(zhí)行
// code...
}];</code></pre>
- 方法四,Spring Animationring Animation):彈簧動(dòng)畫(huà)
在IOS7開(kāi)始,系統(tǒng)動(dòng)畫(huà)效果廣泛應(yīng)用Spring Animation:
<pre><code>[UIView animateWithDuration:4.0 // 動(dòng)畫(huà)時(shí)長(zhǎng)
delay:0.0 // 動(dòng)畫(huà)延遲
usingSpringWithDamping:1.0 // 類似彈簧振動(dòng)效果 0~1
initialSpringVelocity:5.0 // 初始速度
options:UIViewAnimationOptionCurveEaseInOut // 動(dòng)畫(huà)過(guò)渡效果
animations:^{
// code...
CGPoint point = _imageView.center;
point.y += 150;
[_imageView setCenter:point];
} completion:^(BOOL finished) {
// 動(dòng)畫(huà)完成后執(zhí)行
// code...
[_imageView setAlpha:1];
}];
</code></pre>
usingSpringWithDamping:它的范圍為 0.0f 到 1.0f ,數(shù)值越小「彈簧」的振動(dòng)效果越明顯。
initialSpringVelocity:初始的速度,數(shù)值越大一開(kāi)始移動(dòng)越快。值得注意的是,初始速度取值較高而時(shí)間較短時(shí),也會(huì)出現(xiàn)反彈情況。
轉(zhuǎn):Spring Animation 是線性動(dòng)畫(huà)或 ease-out 動(dòng)畫(huà)的理想替代品。由于 iOS 本身大量使用的就是 Spring Animation,用戶已經(jīng)習(xí)慣了這種動(dòng)畫(huà)效果,因此使用它能使 App 讓人感覺(jué)更加自然,用 Apple 的話說(shuō)就是「instantly familiar」。此外,Spring Animation 不只能對(duì)位置使用,它適用于所有可被添加動(dòng)畫(huà)效果的屬性。
-
方法六,關(guān)鍵幀動(dòng)畫(huà):
UIView動(dòng)畫(huà)已經(jīng)具備高級(jí)的方法來(lái)創(chuàng)建動(dòng)畫(huà),而且可以更好地理解和構(gòu)建動(dòng)畫(huà)。IOS7以后蘋(píng)果新加了一個(gè)
animateKeyframesWithDuration
的方法,我們可以使用它來(lái)創(chuàng)建更多更復(fù)雜更酷炫的動(dòng)畫(huà)效果,而不需要去使用到核心動(dòng)畫(huà)(CoreAnimation)。
創(chuàng)建關(guān)鍵幀方法:
<pre><code>/**
- 添加關(guān)鍵幀方法
- @param duration 動(dòng)畫(huà)時(shí)長(zhǎng)
- @param delay 動(dòng)畫(huà)延遲
- @param options 動(dòng)畫(huà)效果選項(xiàng)
- @param animations 動(dòng)畫(huà)執(zhí)行代碼
- @param completion 動(dòng)畫(huà)結(jié)束執(zhí)行代碼
*/
- (void)animateKeyframesWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewKeyframeAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion;
</code></pre>
添加關(guān)鍵幀方法:
<pre><code>/**
- 添加關(guān)鍵幀
- @param frameStartTime 動(dòng)畫(huà)相對(duì)開(kāi)始時(shí)間
- @param frameDuration 動(dòng)畫(huà)相對(duì)持續(xù)時(shí)間
- @param animations 動(dòng)畫(huà)執(zhí)行代碼
*/
- (void)addKeyframeWithRelativeStartTime:(double)frameStartTime
relativeDuration:(double)frameDuration
animations:(void (^)(void))animations;
</code></pre>以上說(shuō)的相對(duì)時(shí)間,也就是說(shuō):“它們自身會(huì)根據(jù)動(dòng)畫(huà)總持續(xù)時(shí)長(zhǎng)自動(dòng)匹配其運(yùn)行時(shí)長(zhǎng)”。
<pre><code>[UIView animateKeyframesWithDuration:4.0
delay:0.0
options:UIViewKeyframeAnimationOptionCalculationModeCubic | UIViewAnimationOptionCurveLinear
animations:keyFrameBlock
completion:^(BOOL finished) {
// 動(dòng)畫(huà)完成后執(zhí)行
// code...
}];
</code></pre>
動(dòng)畫(huà)過(guò)渡效果(Options),新增了以下幾個(gè):
<pre><code>UIViewKeyframeAnimationOptionCalculationModeLinear = 0 << 10, // default
UIViewKeyframeAnimationOptionCalculationModeDiscrete = 1 << 10,
UIViewKeyframeAnimationOptionCalculationModePaced = 2 << 10,
UIViewKeyframeAnimationOptionCalculationModeCubic = 3 << 10,
UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10
</code></pre>
下面我們看一張圖,讓我們更容易理解:

- 方法五,轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
<pre><code>/**
- 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
- @param fromView 當(dāng)前View
- @param toView 要顯示的View
- @param duration 動(dòng)畫(huà)持續(xù)時(shí)間
- @param option 動(dòng)畫(huà)類型
- @param animations 動(dòng)畫(huà)執(zhí)行代碼
- @param completion 動(dòng)畫(huà)結(jié)束后,會(huì)自動(dòng)調(diào)用這個(gè)block
*/
- (void)transitionFromView:(UIView *)fromView
toView:(UIView *)toView
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
completion:(void (^)(BOOL finished))completion;
</code></pre>
小結(jié):
- 如果只是修改控件的屬性,使用首尾式動(dòng)畫(huà)還是比較方便的,但是如果需要在動(dòng)畫(huà)完成后做后續(xù)處理,就不是那么方便了。
- 在實(shí)際的開(kāi)發(fā)中更常用的時(shí)block代碼塊來(lái)處理動(dòng)畫(huà)操作,塊動(dòng)畫(huà)相對(duì)來(lái)說(shuō)比較靈活,尤為重要的是能夠?qū)?dòng)畫(huà)相關(guān)的代碼編寫(xiě)在一起,便于代碼的閱讀和理解。
詳情見(jiàn)
UIViewAnimations Demo
補(bǔ)充
1.UIImageView的幀動(dòng)畫(huà)
UIImageView可以讓一系列的圖片在特定的時(shí)間內(nèi)按順序顯示
相關(guān)屬性解析:
animationImages
:要顯示的圖片(一個(gè)裝著UIImage的NSArray)
animationDuration
:完整地顯示一次animationImages中的所有圖片所需的時(shí)間
animationRepeatCount
:動(dòng)畫(huà)的執(zhí)行次數(shù)(默認(rèn)為0,代表無(wú)限循環(huán))
相關(guān)方法解析:
- (void)startAnimating; 開(kāi)始動(dòng)畫(huà)
- (void)stopAnimating; 停止動(dòng)畫(huà)
- (BOOL)isAnimating; 是否正在運(yùn)行動(dòng)畫(huà)
</code></prep>
- 這種方法在某些場(chǎng)景下是可以達(dá)到逐幀的動(dòng)畫(huà)效果,但是它也存在著很大的性能問(wèn)題,并且這種方法一旦設(shè)置完圖片中間的過(guò)程就無(wú)法控制了。
2.UIActivityIndicatorView
是一個(gè)旋轉(zhuǎn)進(jìn)度輪,可以用來(lái)告知用戶有一個(gè)操作正在進(jìn)行中,一般用initWithActivityIndicatorStyle
初始化
UIActivityIndicatorViewStyle
有3個(gè)值可供選擇:
UIActivityIndicatorViewStyleWhiteLarge //大型白色指示器
UIActivityIndicatorViewStyleWhite //標(biāo)準(zhǔn)尺寸白色指示器
UIActivityIndicatorViewStyleGray //灰色指示器,用于白色背景
方法解析:
- (void)startAnimating; 開(kāi)始動(dòng)畫(huà)
- (void)stopAnimating; 停止動(dòng)畫(huà)
- (BOOL)isAnimating; 是否正在運(yùn)行動(dòng)畫(huà)
3.UIDynamic
一、簡(jiǎn)單介紹
1.什么是UIDynamic
UIDynamic
是從iOS 7開(kāi)始引入的一種新技術(shù),隸屬于UIKit框架可以認(rèn)為是一種物理引擎,能模擬和仿真現(xiàn)實(shí)生活中的物理現(xiàn)象。如:重力、彈性碰撞等現(xiàn)象
2.物理引擎的價(jià)值
廣泛用于游戲開(kāi)發(fā),經(jīng)典成功案例是“憤怒的小鳥(niǎo)”
讓開(kāi)發(fā)人員可以在遠(yuǎn)離物理學(xué)公式的情況下,實(shí)現(xiàn)炫酷的物理仿真效果
提高了游戲開(kāi)發(fā)效率,產(chǎn)生更多優(yōu)秀好玩的物理仿真游戲
3.知名的2D物理引擎
Box2d
Chipmunk
二、使用步驟
要想使用UIDynamic來(lái)實(shí)現(xiàn)物理仿真效果,大致的步驟如下
創(chuàng)建一個(gè)物理仿真器(順便設(shè)置仿真范圍)
創(chuàng)建相應(yīng)的物理仿真行為(順便添加物理仿真元素)
將物理仿真行為添加到物理仿真器中,開(kāi)始仿真
三、相關(guān)說(shuō)明
1.三個(gè)概念
(1)誰(shuí)要進(jìn)行物理仿真?
物理仿真元素(Dynamic Item
)
(2)執(zhí)行怎樣的物理仿真效果?怎樣的動(dòng)畫(huà)效果?
物理仿真行為(Dynamic Behavior
)
(3)讓物理仿真元素執(zhí)行具體的物理仿真行為
物理仿真器(Dynamic Animator
)
2.物理仿真元素
注意:
- 不是任何對(duì)象都能做物理仿真元素
- 不是任何對(duì)象都能進(jìn)行物理仿真
物理仿真元素要素:
任何遵守了
UIDynamicItem
協(xié)議的對(duì)象UIView
默認(rèn)已經(jīng)遵守了UIDynamicItem
協(xié)議,因此任何UI控件都能做物理仿真UICollectionViewLayoutAttributes
類默認(rèn)也遵守UIDynamicItem
協(xié)議
3.物理仿真行為
(1)UIDynamic提供了以下幾種物理仿真行為
UIGravityBehavior
:重力行為UICollisionBehavior
:碰撞行為UISnapBehavior
:捕捉行為UIPushBehavior
:推動(dòng)行為UIAttachmentBehavior
:附著行為UIDynamicItemBehavior
:動(dòng)力元素行為
(2)物理仿真行為須知
上述所有物理仿真行為都繼承自
UIDynamicBehavior
所有的
UIDynamicBehavior
都可以獨(dú)立進(jìn)行組合使用多種行為時(shí),可以實(shí)現(xiàn)一些比較復(fù)雜的效果
4. 物理仿真器
(1)物理仿真器須知
它可以讓物理仿真元素執(zhí)行物理仿真行為
它是
UIDynamicAnimator
類型的對(duì)象
(2)UIDynamicAnimator
的初始化
-
- (instancetype)initWithReferenceView:(UIView *)view;
view參數(shù):是一個(gè)參照視圖,表示物理仿真的范圍
5.物理仿真器的說(shuō)明
(1)UIDynamicAnimator
的常見(jiàn)方法
- (void)addBehavior:(UIDynamicBehavior *)behavior;
//添加1個(gè)物理仿真行為
- (void)removeBehavior:(UIDynamicBehavior *)behavior;
//移除1個(gè)物理仿真行為
- (void)removeAllBehaviors;
//移除之前添加過(guò)的所有物理仿真行為
(2)UIDynamicAnimator
的常見(jiàn)屬性
@property (nonatomic, readonly) UIView* referenceView;
//參照視圖
@property (nonatomic, readonly, copy) NSArray* behaviors;
//添加到物理仿真器中的所有物理仿真行為
@property (nonatomic, readonly, getter = isRunning) BOOL running;
//是否正在進(jìn)行物理仿真
@property (nonatomic, assign) id <UIDynamicAnimatorDelegate> delegate;
//代理對(duì)象(能監(jiān)聽(tīng)物理仿真器的仿真過(guò)程,比如開(kāi)始和結(jié)束)
詳情見(jiàn)
DynamicAnimationDemo
================
二、Core Animation
什么是Animation(動(dòng)畫(huà)),簡(jiǎn)單點(diǎn)說(shuō)就是在一段時(shí)間內(nèi),顯示的內(nèi)容發(fā)生了變化.對(duì)CALayer來(lái)說(shuō)就是在一段時(shí)間內(nèi),其Animatable Property發(fā)生了變化.
這里涉及到兩個(gè)東西: 一是Layer(基類CALayer),一是Animation(基于CAAnimation). Animation作用于Layer.CALayer提供了接口用于給自己添加Animation.
Core Animation是一組非常強(qiáng)大的動(dòng)畫(huà)處理API,使用它能做出非常絢麗的動(dòng)畫(huà)效果,而且往往是事半功倍,使用它需要添加QuartzCore .framework和引入對(duì)應(yīng)的框架<QuartzCore/QuartzCore.h> .
開(kāi)發(fā)步驟:
1> 初始化一個(gè)動(dòng)畫(huà)對(duì)象(CAAnimation)并設(shè)置一些動(dòng)畫(huà)相關(guān)屬性.
2> 添加動(dòng)畫(huà)對(duì)象到層(CALayer)中,開(kāi)始執(zhí)行動(dòng)畫(huà).
Core Animation的動(dòng)畫(huà)執(zhí)行過(guò)程都是在后臺(tái)操作的,不會(huì)阻塞主線程.
1. CALayer
CALayer與UIView的關(guān)系
在iOS中,你能看得見(jiàn)摸得著的東西基本上都是UIView,比如一個(gè)按鈕、一個(gè)文本標(biāo)簽、一個(gè)文本輸入框、一個(gè)圖標(biāo)等等,這些都是UIView。
其實(shí)UIView之所以能顯示在屏幕上,完全是因?yàn)樗鼉?nèi)部的一個(gè)圖層:
-
在創(chuàng)建UIView對(duì)象時(shí),UIView內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)圖層(即CALayer對(duì)象),通過(guò)UIView的layer屬性可以訪問(wèn)這個(gè)層。
@property(nonatomic,readonly,strong) CALayer *layer;
當(dāng)UIView需要顯示到屏幕上時(shí),會(huì)調(diào)用drawRect:方法進(jìn)行繪圖,并且會(huì)將所有內(nèi)容繪制在自己的圖層上,繪圖完畢后,系統(tǒng)會(huì)將圖層拷貝到屏幕上,于是就完成了UIView的顯示。
換句話說(shuō),UIView本身不具備顯示的功能,是它內(nèi)部的層才有顯示功能。
因此,通過(guò)調(diào)節(jié)CALayer對(duì)象,可以很方便的調(diào)整UIView的一些外觀屬性。
- 對(duì)比CALayer,UIView多了一個(gè)事件處理的功能。也就是說(shuō),CALayer不能處理用戶的觸摸事件,而UIView可以。所以,如果顯示出來(lái)的東西需要跟用戶進(jìn)行交互的話,用UIView;如果不需要跟用戶進(jìn)行交互,用UIView或者CALayer都可以。當(dāng)然,CALayer的性能會(huì)高一些,因?yàn)樗倭耸录幚淼墓δ埽虞p量級(jí)。
Layer的渲染架構(gòu)
Layer也和View一樣存在著一個(gè)層級(jí)樹(shù)狀結(jié)構(gòu),稱之為圖層樹(shù)(Layer Tree
),直接創(chuàng)建的或者通過(guò)UIView獲得的(view.layer)用于顯示的圖層樹(shù),稱之為模型樹(shù)(Model Tree
),模型樹(shù)的背后還存在兩份圖層樹(shù)的拷貝,一個(gè)是呈現(xiàn)樹(shù)(Presentation Tree
),一個(gè)是渲染樹(shù)(Render Tree
)。
呈現(xiàn)樹(shù)可以通過(guò)普通layer(其實(shí)就是模型樹(shù))的layer.presentationLayer獲得,而模型樹(shù)則可以通過(guò)modelLayer屬性獲得。
- 模型樹(shù)的屬性在其被修改的時(shí)候就變成了新的值,這個(gè)是可以用代碼直接操控的部分;
- 呈現(xiàn)樹(shù)的屬性值和動(dòng)畫(huà)運(yùn)行過(guò)程中界面上看到的是一致的;
- 渲染樹(shù)是私有的,你無(wú)法訪問(wèn)到,渲染樹(shù)是對(duì)呈現(xiàn)樹(shù)的數(shù)據(jù)進(jìn)行渲染。
為了不阻塞主線程,渲染的過(guò)程是在單獨(dú)的進(jìn)程或線程中進(jìn)行的,所以你會(huì)發(fā)現(xiàn)Animation的動(dòng)畫(huà)并不會(huì)阻塞主線程.
隱式動(dòng)畫(huà)
根層與非根層:
每一個(gè)UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個(gè)CALayer,我們可用稱這個(gè)Layer為Root Layer(根層)
所有的非Root Layer,也就是手動(dòng)創(chuàng)建的CALayer對(duì)象,都存在著隱式動(dòng)畫(huà)
當(dāng)對(duì)非Root Layer的部分屬性進(jìn)行修改時(shí),默認(rèn)會(huì)自動(dòng)產(chǎn)生一些動(dòng)畫(huà)效果,而這些屬性稱為Animatable Properties(可動(dòng)畫(huà)屬性)。
可以通過(guò)事務(wù)關(guān)閉隱式動(dòng)畫(huà):
CATransaction 是核心動(dòng)畫(huà)里面負(fù)責(zé)協(xié)調(diào)多個(gè)動(dòng)畫(huà)原子更新顯示操作。事務(wù)支持嵌套使用。
<pre><code>[CATransaction begin];
// 關(guān)閉隱式動(dòng)畫(huà)
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];</code></pre>
CALayer的基本屬性
<pre><code>position和anchorPoint的作用
@property CGPoint position;
用來(lái)設(shè)置CALayer在父層中的位置
以父層的左上角為原點(diǎn)(0, 0)
@property CGPoint anchorPoint;
稱為“定位點(diǎn)”、“錨點(diǎn)”,
決定著CALayer身上的哪個(gè)點(diǎn)會(huì)在position屬性所指的位置。
以自己的左上角為原點(diǎn)(0, 0),
它的x、y取值范圍都是0~1,默認(rèn)值為中心點(diǎn)(0.5, 0.5)
anchorPoint和position的關(guān)系舉例:
假如錨點(diǎn)anchorPoint為默認(rèn)值即中點(diǎn)(0.5,0.5),而該層的position設(shè)置為(0,0)即為父層的左上點(diǎn),那么該層在父層中只會(huì)看到四分之一的部分。
</code></pre>
為了進(jìn)一步說(shuō)明anchorPoint的作用,假設(shè)有一個(gè)層大小100*100,現(xiàn)在中心點(diǎn)位置(50,50),由此可以得出frame(0,0,100,100)。上面說(shuō)過(guò)anchorPoint默認(rèn)為(0.5,0.5),同中心點(diǎn)position重合,此時(shí)使用圖形描述如圖1;當(dāng)修改anchorPoint為(0,0),此時(shí)錨點(diǎn)處于圖層左上角,但是中心點(diǎn)poition并不會(huì)改變,因此圖層會(huì)向右下角移動(dòng),如圖2;然后修改anchorPoint為(1,1,),position還是保持位置不變,錨點(diǎn)處于圖層右下角,此時(shí)圖層如圖3。
2.CAAnimation概述
當(dāng)需要對(duì)非Root Layer進(jìn)行動(dòng)畫(huà)或者需要對(duì)動(dòng)畫(huà)做更多自定義的行為的時(shí)候,就必須使用到顯式動(dòng)畫(huà)了,顯式動(dòng)畫(huà)的基類為CAAnimation,顯式動(dòng)畫(huà)不會(huì)改變?cè)搶傩缘闹?它只是用于動(dòng)畫(huà)顯示。
- 采用了
CAMediaTiming
協(xié)議:可以調(diào)整時(shí)間,包括持續(xù)時(shí)間,速度,重復(fù)次數(shù),并且能設(shè)定圖層過(guò)渡; - 采用了
CAAction
協(xié)議:可以通過(guò)響應(yīng)動(dòng)作的方式來(lái)顯示動(dòng)畫(huà).
來(lái)看下CAAnimation的繼承體系
CAAnimation是個(gè)抽象類,不具備動(dòng)畫(huà)效果,必須用它的子類才有動(dòng)畫(huà)效果。
-
CAPropertyAnimation也是個(gè)抽象類,本身不具備動(dòng)畫(huà)效果,只有子類才有。
CABasicAnimation和CAKeyframeAnimation:
CABasicAnimation基本動(dòng)畫(huà),做一些簡(jiǎn)單效果。
CAKeyframeAnimation關(guān)鍵幀動(dòng)畫(huà),做一些連續(xù)的流暢的動(dòng)畫(huà)。
- CAAnimationGroup是個(gè)動(dòng)畫(huà)組,可以同時(shí)進(jìn)行縮放,旋轉(zhuǎn)(同時(shí)進(jìn)行多個(gè)動(dòng)畫(huà))。
- CATransition是轉(zhuǎn)場(chǎng)動(dòng)畫(huà),界面之間跳轉(zhuǎn)(切換)都可以用轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。
1)CAAnimation——簡(jiǎn)介
是所有動(dòng)畫(huà)對(duì)象的父類,負(fù)責(zé)控制動(dòng)畫(huà)的持續(xù)時(shí)間和速度,是個(gè)抽象類,不能直接使用,應(yīng)該使用它具體的子類。
基本屬性說(shuō)明:
duration
:動(dòng)畫(huà)的持續(xù)時(shí)間repeatCount
:重復(fù)次數(shù),無(wú)限循環(huán)可以設(shè)置HUGE_VALF或者M(jìn)AXFLOATrepeatDuration
: 重復(fù)時(shí)間removedOnCompletion
:默認(rèn)為YES,代表動(dòng)畫(huà)執(zhí)行完畢后就從圖層上移除,圖形會(huì)恢復(fù)到動(dòng)畫(huà)執(zhí)行前的狀態(tài)。如果想讓圖層保持顯示動(dòng)畫(huà)執(zhí)行后的狀態(tài),那就設(shè)置為NO,不過(guò)還要設(shè)置fillMode為kCAFillModeForwards-
fillMode
: 決定當(dāng)前對(duì)象在非active時(shí)間段的行為。比如動(dòng)畫(huà)開(kāi)始之前或者動(dòng)畫(huà)結(jié)束之fillMode
屬性的設(shè)置:kCAFillModeRemoved 這個(gè)是默認(rèn)值,也就是說(shuō)當(dāng)動(dòng)畫(huà)開(kāi)始前和動(dòng)畫(huà)結(jié)束后,動(dòng)畫(huà)對(duì)layer都沒(méi)有影響,動(dòng)畫(huà)結(jié)束后,layer會(huì)恢復(fù)到之前的狀態(tài) kCAFillModeForwards 當(dāng)動(dòng)畫(huà)結(jié)束后,layer會(huì)一直保持著動(dòng)畫(huà)最后的狀態(tài) kCAFillModeBackwards 在動(dòng)畫(huà)開(kāi)始前,只需要將動(dòng)畫(huà)加入了一個(gè)layer,layer便立即進(jìn)入動(dòng)畫(huà)的初始狀態(tài)并等待動(dòng)畫(huà)開(kāi)始。 kCAFillModeBoth 這個(gè)其實(shí)就是上面兩個(gè)的合成.動(dòng)畫(huà)加入后開(kāi)始之前,layer便處于動(dòng)畫(huà)初始狀態(tài),動(dòng)畫(huà)結(jié)束后layer保持動(dòng)畫(huà)最后的狀態(tài)
beginTime
: 可以用來(lái)設(shè)置動(dòng)畫(huà)延遲執(zhí)行時(shí)間,若想延遲2s,就設(shè)置為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當(dāng)前時(shí)間-
timingFunction
: 速度控制函數(shù),控制動(dòng)畫(huà)運(yùn)行的節(jié)奏速度控制函數(shù)(
CAMediaTimingFunction
):kCAMediaTimingFunctionLinear(線性):勻速,給你一個(gè)相對(duì)靜態(tài)的感覺(jué) kCAMediaTimingFunctionEaseIn(漸進(jìn)):動(dòng)畫(huà)緩慢進(jìn)入,然后加速離開(kāi) kCAMediaTimingFunctionEaseOut(漸出):動(dòng)畫(huà)全速進(jìn)入,然后減速的到達(dá)目的地 kCAMediaTimingFunctionEaseInEaseOut(漸進(jìn)漸出):動(dòng)畫(huà)緩慢的進(jìn)入,中間加速,然后減速的到達(dá)目的地。這個(gè)是默認(rèn)的動(dòng)畫(huà)行為>
delegate
:動(dòng)畫(huà)代理
CAAnimation在分類中定義了代理方法
<pre><code>
@interface NSObject (CAAnimationDelegate)
/* Called when the animation begins its active duration. */
// 動(dòng)畫(huà)開(kāi)始時(shí)調(diào)用
- (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. */
// 動(dòng)畫(huà)結(jié)束后調(diào)用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end</code></pre>
2)CAPropertyAnimation
是CAAnimation的子類,也是個(gè)抽象類,要想創(chuàng)建動(dòng)畫(huà)對(duì)象,應(yīng)該使用它的兩個(gè)子類:CABasicAnimation
和CAKeyframeAnimation
。
基本屬性說(shuō)明:
keyPath: 通過(guò)指定CALayer的一個(gè)屬性名稱為keyPath(NSString類型),并且對(duì)CALayer的這個(gè)屬性的值進(jìn)行修改,達(dá)到相應(yīng)的動(dòng)畫(huà)效果。比如,指定@“position”為keyPath,就修改CALayer的position屬性的值,以達(dá)到平移的動(dòng)畫(huà)效果
CABasicAnimation——基本動(dòng)畫(huà)
屬性說(shuō)明:
fromValue: keyPath相應(yīng)屬性的初始值
toValue: keyPath相應(yīng)屬性的結(jié)束值
byValue: keyPath相應(yīng)屬性的改變值
動(dòng)畫(huà)過(guò)程說(shuō)明:
隨著動(dòng)畫(huà)的進(jìn)行,在長(zhǎng)度為duration的持續(xù)時(shí)間內(nèi),keyPath相應(yīng)屬性的值從fromValue漸漸地變?yōu)閠oValue。
keyPath內(nèi)容是CALayer的可動(dòng)畫(huà)Animatable屬性。
如果fillMode = kCAFillModeForwards同時(shí)removedOnComletion = NO,那么在動(dòng)畫(huà)執(zhí)行完畢后,圖層會(huì)保持顯示動(dòng)畫(huà)執(zhí)行后的狀態(tài)。但在實(shí)質(zhì)上,圖層的屬性值還是動(dòng)畫(huà)執(zhí)行前的初始值,并沒(méi)有真正被改變。
CAKeyframeAnimation——關(guān)鍵幀動(dòng)畫(huà)
關(guān)鍵幀動(dòng)畫(huà),也是CAPropertyAnimation的子類,與CABasicAnimation的區(qū)別是:
CABasicAnimation
只能從一個(gè)數(shù)值(fromValue
)變到另一個(gè)數(shù)值(toValue
),而CAKeyframeAnimation
會(huì)使用一個(gè)NSArray
保存這些數(shù)值
CABasicAnimation可看做是只有2個(gè)關(guān)鍵幀的CAKeyframeAnimation
屬性說(shuō)明:
values
: NSArray對(duì)象。里面的元素稱為“關(guān)鍵幀”(keyframe)。動(dòng)畫(huà)對(duì)象會(huì)在指定的時(shí)間(duration)內(nèi),依次顯示values數(shù)組中的每一個(gè)關(guān)鍵幀
path
: 可以設(shè)置一個(gè)CGPathRef、CGMutablePathRef,讓圖層按照路徑軌跡移動(dòng)。path只對(duì)CALayer的anchorPoint和position起作用。如果設(shè)置了path,那么values將被忽略
keyTimes
: 可以為對(duì)應(yīng)的關(guān)鍵幀指定對(duì)應(yīng)的時(shí)間點(diǎn),其取值范圍為0到1.0,keyTimes中的每一個(gè)時(shí)間值都對(duì)應(yīng)values中的每一幀。如果沒(méi)有設(shè)置keyTimes,各個(gè)關(guān)鍵幀的時(shí)間是平分的
3)CAAnimationGroup——?jiǎng)赢?huà)組
動(dòng)畫(huà)組,是CAAnimation
的子類,可以保存一組動(dòng)畫(huà)對(duì)象,將CAAnimationGroup
對(duì)象加入層后,組中所有動(dòng)畫(huà)對(duì)象可以同時(shí)并發(fā)運(yùn)行。
默認(rèn)情況下,一組動(dòng)畫(huà)對(duì)象是同時(shí)運(yùn)行的,也可以通過(guò)設(shè)置動(dòng)畫(huà)對(duì)象的beginTime
屬性來(lái)更改動(dòng)畫(huà)的開(kāi)始時(shí)間。
屬性說(shuō)明:
animations
: 用來(lái)保存一組動(dòng)畫(huà)對(duì)象的NSArray
4)CATransition——轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
CATransition是CAAnimation的子類,用于做轉(zhuǎn)場(chǎng)動(dòng)畫(huà),能夠?yàn)閷犹峁┮瞥銎聊缓鸵迫肫聊坏膭?dòng)畫(huà)效果。iOS比Mac OS X的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)效果少一點(diǎn)。
UINavigationController就是通過(guò)CATransition實(shí)現(xiàn)了將控制器的視圖推入屏幕的動(dòng)畫(huà)效果。
屬性說(shuō)明:
type
: 動(dòng)畫(huà)過(guò)渡類型
subtype
: 動(dòng)畫(huà)過(guò)度方向
startProgress
: 動(dòng)畫(huà)起點(diǎn)(在整體動(dòng)畫(huà)的百分比)
endProgress
: 動(dòng)畫(huà)終點(diǎn)(在整體動(dòng)畫(huà)的百分比)
步驟
1.創(chuàng)建轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
2.設(shè)置轉(zhuǎn)場(chǎng)類型、子類型(可選)及其他屬性
3.設(shè)置轉(zhuǎn)場(chǎng)后的新視圖并添加動(dòng)畫(huà)到圖層
舉例
<pre><code>CATransition *anim = [CATransition animation];
anim.type = @"cube";
anim.subtype = kCATransitionFromBottom;
[view.layer addAnimation:anim forKey:nil];
</code></pre>
詳情見(jiàn)KKCoreAnimation
&&SKBounceAnimation
3.補(bǔ)充
1)CASpringAnimation
iOS9才引入的動(dòng)畫(huà)類,它繼承于CABaseAnimation,用于制作彈簧動(dòng)畫(huà)
參數(shù)說(shuō)明
mass
://質(zhì)量,影響圖層運(yùn)動(dòng)時(shí)的彈簧慣性,質(zhì)量越大,彈簧拉伸和壓縮的幅度越大,動(dòng)畫(huà)的速度變慢,并且波動(dòng)幅度變大
stiffness
://剛度系數(shù)(勁度系數(shù)/彈性系數(shù)),剛度系數(shù)越大,形變產(chǎn)生的力就越大,運(yùn)動(dòng)越快
damping
://阻尼系數(shù),阻止彈簧伸縮的系數(shù),阻尼系數(shù)越大,停止越快
initialVelocity
://初始速率,動(dòng)畫(huà)視圖的初始速度大小
速率為正數(shù)時(shí),速度方向與運(yùn)動(dòng)方向一致,速率為負(fù)數(shù)時(shí),速度方向與運(yùn)動(dòng)方向相反
settlingDuration
://結(jié)算時(shí)間 返回彈簧動(dòng)畫(huà)到停止時(shí)的估算時(shí)間,根據(jù)當(dāng)前的動(dòng)畫(huà)參數(shù)估算
通常彈簧動(dòng)畫(huà)的時(shí)間使用結(jié)算時(shí)間比較準(zhǔn)確
2)CAShapeLayer:
CAShapeLayer顧名思義,繼承于CALayer。 每個(gè)CAShapeLayer對(duì)象都代表著將要被渲染到屏幕上的一個(gè)任意的形狀(shape)。具體的形狀由其path(類型為CGPathRef)屬性指定。 普通的CALayer是矩形,所以需要frame屬性。CAShapeLayer初始化時(shí)也需要指定frame值,但 它本身沒(méi)有形狀,它的形狀來(lái)源于其屬性path 。CAShapeLayer有不同于CALayer的屬性,它從CALayer繼承而來(lái)的屬性在繪制時(shí)是不起作用的。
3)CADisplayLink
CADisplayLink是一個(gè)計(jì)時(shí)器,但是同NSTimer不同的是,CADisplayLink的刷新周期同屏幕完全一致。例如在iOS中屏幕刷新周期是60次/秒,CADisplayLink刷新周期同屏幕刷新一致也是60次/秒,這樣一來(lái)使用它完成的逐幀動(dòng)畫(huà)(又稱為“時(shí)鐘動(dòng)畫(huà)”)完全感覺(jué)不到動(dòng)畫(huà)的停滯情況。
iOS程序在運(yùn)行后就進(jìn)入一個(gè)消息循環(huán)中(這個(gè)消息循環(huán)稱為“主運(yùn)行循環(huán)”),整個(gè)程序相當(dāng)于進(jìn)入一個(gè)死循環(huán)中,始終等待用戶輸入。將CADisplayLink加入到主運(yùn)行循環(huán)隊(duì)列后,它的時(shí)鐘周期就和主運(yùn)行循環(huán)保持一致,而主運(yùn)行循環(huán)周期就是屏幕刷新周期。在CADisplayLink加入到主運(yùn)行循環(huán)隊(duì)列后就會(huì)循環(huán)調(diào)用目標(biāo)方法,在這個(gè)方法中更新視圖內(nèi)容就可以完成逐幀動(dòng)畫(huà)。
使用方法:
<pre><code>定義CADisplayLink并制定觸發(fā)調(diào)用方法
將顯示鏈接添加到主運(yùn)行循環(huán)隊(duì)列
// 定義
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotationChange)];
// 添加到主循環(huán)隊(duì)列
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
開(kāi)始和暫停
// 暫停
link.paused = YES;
// 開(kāi)始
link.paused = NO;
</code></pre>
三、FaceBook POP動(dòng)畫(huà)
1.工作機(jī)制
POP是一個(gè)在iOS與OS X上通用的極具擴(kuò)展性的動(dòng)畫(huà)引擎 它在基本的靜態(tài)動(dòng)畫(huà)的基礎(chǔ)上增加的彈簧動(dòng)畫(huà)與衰減動(dòng)畫(huà)。
使之能創(chuàng)造出更真實(shí)更具物理性的交互動(dòng)畫(huà) POP的API可以快速的與現(xiàn)有的ObjC代碼集成并可以作用于任意對(duì)象的任意屬性。
POP 本質(zhì)上是基于定時(shí)器的動(dòng)畫(huà)庫(kù),使用每秒 60 頻率的定時(shí)器,即時(shí)鐘頻率為 1/60 秒(為了匹配 iOS 顯示屏幀率),使得動(dòng)畫(huà)刷新繪制頻率與屏幕刷新頻率一致。很多這類動(dòng)畫(huà)庫(kù)都使用 CADisplayLink 做為一個(gè)回調(diào)源。
在計(jì)算機(jī)的世界里面,其實(shí)并不存在絕對(duì)連續(xù)的動(dòng)畫(huà),你所看到的屏幕上的動(dòng)畫(huà)本質(zhì)上都是離散的,只是在一秒的時(shí)間里面離散的幀多到一定的數(shù)量人眼就覺(jué)得是連續(xù)的了,在iOS中,最大的幀率是60幀每秒。 iOS提供了Core Animation框架,只需要開(kāi)發(fā)者提供關(guān)鍵幀信息,比如提供某個(gè)animatable屬性終點(diǎn)的關(guān)鍵幀信息,然后中間的值則通過(guò)一定的算法進(jìn)行插值計(jì)算,從而實(shí)現(xiàn)補(bǔ)間動(dòng)畫(huà)。 Core Aniamtion中進(jìn)行插值計(jì)算所依賴的時(shí)間曲線由CAMediaTimingFunction提供。 Pop Animation在使用上和Core Animation很相似,都涉及Animation對(duì)象以及Animation的載體的概念,不同的是Core Animation的載體只能是CALayer,而Pop Animation可以是任意基于NSObject的對(duì)象。當(dāng)然大多數(shù)情況Animation都是界面上顯示的可視的效果,所以動(dòng)畫(huà)執(zhí)行的載體一般都直接或者間接是UIView或者CALayer。
-
Pop Animation相比于Core Animation的優(yōu)點(diǎn)
1. Pop Animation應(yīng)用于CALayer時(shí),在動(dòng)畫(huà)運(yùn)行的任何時(shí)刻,layer和其presentationLayer的相關(guān)屬性值始終保持一致,而Core Animation做不到。 2.Pop Animation可以應(yīng)用任何NSObject的對(duì)象,而Core Aniamtion必須是CALayer。
2.源碼結(jié)構(gòu):
代碼包括四個(gè)目錄:
Animations: 定義pop支持的動(dòng)畫(huà)類型,并抽像各種動(dòng)畫(huà)的低層數(shù)據(jù)結(jié)構(gòu)
Engine:組織動(dòng)化運(yùn)行的數(shù)據(jù)結(jié)構(gòu),核心是動(dòng)化管理者,還包括了動(dòng)畫(huà)引擎所需要的可動(dòng)畫(huà)屬性定義、動(dòng)畫(huà)追蹤等內(nèi)容
Utility: 封裝Engine中用到的各種功能,包括數(shù)值運(yùn)算,數(shù)據(jù)轉(zhuǎn)換,運(yùn)算等
WebCore: 這部分是蘋(píng)果公司的代碼,矩陣運(yùn)算和貝賽爾曲線的,用于底層運(yùn)算。
1)Animations
POPAnimation :定義了動(dòng)畫(huà)基類POPAnimation
私有變量:結(jié)構(gòu)體`_POPAnimationState` 紀(jì)錄動(dòng)畫(huà)狀態(tài),是實(shí)現(xiàn)動(dòng)畫(huà)最關(guān)鍵的屬性
公有變量:name beginTime delegate tracer(動(dòng)畫(huà)追蹤,紀(jì)錄各種動(dòng)畫(huà)事件) ^completionBlock removedOnCompletion paused
繼承關(guān)系:
NSObject
POPAnimation
POPPropertyAnimation
POPBasicAnimation
POPDecayAnimation
POPSpringAnimation
POPCustomAnimation
_POPAnimationState
_POPPropertyAnimationState
_POPBasicAnimationState
_POPDecayAnimationState
_POPSpringAnimationState
NSObject (POP)讓所有對(duì)象增加pop動(dòng)畫(huà)支持(增刪改查)通過(guò)POPAnimator進(jìn)行管理
2)Engine
POPAnimateableProperty 可動(dòng)畫(huà)的屬性,用于定義動(dòng)畫(huà)類型和動(dòng)畫(huà)時(shí)修改值
POPStaticAnimatablePropertyState 結(jié)構(gòu)體紀(jì)錄了屬性名,readBlock,writeBlock,和域值
POPStaticAnimatablePropertyState _staticStates[] 紀(jì)錄了所有可動(dòng)畫(huà)的屬性對(duì)應(yīng)的名稱,其中的writeblock功能是把二進(jìn)制數(shù)據(jù)寫(xiě)到對(duì)應(yīng)的屬性里
類族:
POPAnimatableProperty
POPConcreteAnimatableProperty
POPMutableAnimatableProperty
POPPlaceholderAnimatableProperty
POPStaticAnimatableProperty
POPAnimationEvent POPAnimationTracer的基本元素
POPAnimationExtras 擴(kuò)展CAAnimation 和POPSpringAnimation 的方法(分類)
POPAnimationRuntime 這里有幾個(gè)函數(shù)比較特殊
POPBox 包裝一個(gè)函數(shù)vector,把vector轉(zhuǎn)化為point,size,rect,color等
POPUnbox 解包一個(gè)向量,把point,size,rect,color對(duì)象轉(zhuǎn)換為vector
POPAnimationTracer 動(dòng)畫(huà)跟蹤 通過(guò)POPAnimationEvent來(lái)描述
POPAnimator 動(dòng)畫(huà)管理者,紀(jì)錄所有的動(dòng)畫(huà)事件(POPAnimatorItem,紀(jì)錄了動(dòng)畫(huà)作用到的對(duì)象、動(dòng)畫(huà)key、動(dòng)畫(huà)對(duì)象等信息),初始化是把CADisplayLink注冊(cè)到runloop里定時(shí)觸發(fā)render過(guò)程,進(jìn)行一幀動(dòng)畫(huà)渲染。她提供了add、remove等操作Animation集合的方法,并提供了Observer和delegate等事件函數(shù)
POPAnimator通過(guò)兩層(key,view)存儲(chǔ)動(dòng)畫(huà),(動(dòng)畫(huà)目標(biāo)對(duì)象,(動(dòng)畫(huà)key,動(dòng)畫(huà)對(duì)象))
具體每幀的渲染過(guò)程有兩步:1.renderTime,更新state的狀態(tài)。 2.updateAnimatable,把state的變化更新到obj的具體屬性上
3)Utility 各種工具類
POPAction: ActionDisabler和ActionEnabler 利用RAII暫停核心動(dòng)畫(huà)以ActionEnabler為例,創(chuàng)建ActionEnabler時(shí)停止動(dòng)畫(huà),銷毀時(shí)重新運(yùn)行動(dòng)畫(huà)
POPCGUtils:顏色轉(zhuǎn)換函數(shù),數(shù)組和點(diǎn),point,size,rect,color等轉(zhuǎn)換函數(shù)
POPGeometry:擴(kuò)展NSValue到POP自定義類型的轉(zhuǎn)換
POPLayerExtras:圖層矩陣變換封裝,底層由TransformationMatrix實(shí)現(xiàn)
POPMath:數(shù)學(xué)計(jì)算接口,封裝了UnitBezier,POPVector和其他數(shù)字計(jì)算
SpringSolver:spring插值計(jì)算
POPVector:向量運(yùn)算
4)WebCore
FloatConversion:浮點(diǎn)數(shù)轉(zhuǎn)換方法,提供double->float和double->CGFloat,
用途:服務(wù)于矩陣運(yùn)算
TransformationMatrix:矩陣運(yùn)算,包括初始化,scale,rotate,translate,flipX,flipY,skew,applyPerspective???,multVecMatrix向量和矩陣相乘等矩陣操作,
CATransform3D 矩陣變換之立方體旋轉(zhuǎn)實(shí)現(xiàn)細(xì)節(jié)
關(guān)鍵方法說(shuō)明:
計(jì)算行列式的值:不列舉了,很枯燥,行列式計(jì)算的基本概念,從二階計(jì)算到三階再計(jì)算到四階。主要作用是引擎層對(duì)layer進(jìn)行坐標(biāo)變換
UnitBezier: 結(jié)構(gòu)體,初始化參數(shù)為兩個(gè)控制點(diǎn)p1(p1x,p1y),p2(p2x,p2y),用于表示起始點(diǎn)為s(0,0),終止點(diǎn)為e(1,1),p1為第一控制點(diǎn),p2為第二控制點(diǎn)的二次Bezier。
用途:重新實(shí)現(xiàn)系統(tǒng)的自帶動(dòng)畫(huà)
方法說(shuō)明:
UnitBezier(double p1x, double p1y, double p2x, double p2y)//用兩個(gè)控制點(diǎn)的坐標(biāo)初始化曲線,
double sampleCurveX(double t)//通過(guò)參數(shù)t計(jì)算對(duì)應(yīng)的x值
double sampleCurveY(double t)//通過(guò)參數(shù)t計(jì)算對(duì)應(yīng)的y值
double sampleCurveDerivativeX(double t)
//epsilon表示一個(gè)小間距,相當(dāng)于數(shù)學(xué)計(jì)算里的dX,一般為全距離的1/1000,
//求解x對(duì)應(yīng)的t值,用到了函數(shù)sampleCurveDerivativeX
double solveCurveX(double x, double epsilon)
double solve(double x, double epsilon)//求解x對(duì)應(yīng)的y值,分為兩步算,1.由x計(jì)算t;2.由t計(jì)算y
3.動(dòng)畫(huà)執(zhí)行流程:
1)POPAnimator是單例對(duì)象,初始化對(duì)象實(shí)例時(shí)注冊(cè)把CADisplayLink到runloop,定時(shí)調(diào)用render,通過(guò)renderTime函數(shù)遍歷所有正在執(zhí)行的動(dòng)畫(huà),使動(dòng)畫(huà)進(jìn)行到下一幀,并刷新畫(huà)面,直到所有動(dòng)畫(huà)推進(jìn)完成。
2)動(dòng)畫(huà)狀態(tài)的推進(jìn)最終都是通過(guò)_POPAnimationState類和其子類的advance方法推進(jìn)的,advance更新時(shí)間戳,updateAnimatable方法把state的狀態(tài)變更到動(dòng)畫(huà)要作用的obj對(duì)象。
3)Spring、Decay、Basic 都有各自實(shí)現(xiàn)的advance函數(shù)計(jì)算,而Custom方式不同,他是通過(guò)一個(gè)POPCustomAnimationBlock類型的回調(diào)來(lái)就算這一幀的值的。
4.動(dòng)畫(huà)使用
1)POPBasicAnimation
基本動(dòng)畫(huà),接口方面和CABasicAniamtion很相似,使用可以提供初始值fromValue,這個(gè) 終點(diǎn)值toValue,動(dòng)畫(huà)時(shí)長(zhǎng)duration以及決定動(dòng)畫(huà)節(jié)奏的timingFunction。timingFunction直接使用的CAMediaTimingFunction,是使用一個(gè)橫向縱向都為一個(gè)單位的擁有兩個(gè)控制點(diǎn)的貝賽爾曲線來(lái)描述的,橫坐標(biāo)為時(shí)間,縱坐標(biāo)為動(dòng)畫(huà)進(jìn)度。
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
彈簧動(dòng)畫(huà)是Bezier曲線無(wú)法表述的,所以無(wú)法使用PopBasicAniamtion來(lái)實(shí)現(xiàn)。PopSpringAnimation便是專門(mén)用來(lái)實(shí)現(xiàn)彈簧動(dòng)畫(huà)的。
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],默認(rèn)值為4springSpeed
彈簧速度,速度越快,動(dòng)畫(huà)時(shí)間越短 [0, 20],默認(rèn)為12,和springBounciness一起決定著彈簧動(dòng)畫(huà)的效果dynamicsTension
彈簧的張力dynamicsFriction
彈簧摩擦dynamicsMass
質(zhì)量 。張力,摩擦,質(zhì)量這三者可以從更細(xì)的粒度上替代springBounciness和springSpeed控制彈簧動(dòng)畫(huà)的效果
3)PopDecayAnimation
基于Bezier曲線的timingFuntion同樣無(wú)法表述Decay Aniamtion,所以Pop就單獨(dú)實(shí)現(xiàn)了一個(gè) PopDecayAnimation,用于衰減動(dòng)畫(huà)。衰減動(dòng)畫(huà)一個(gè)很常見(jiàn)的地方就是 UIScrollView 滑動(dòng)松開(kāi)后的減速,這里就基于UIView實(shí)現(xiàn)一個(gè)自己的ScrollView,然后使用PopDecayAnimation實(shí)現(xiàn) 此代碼可以詳細(xì)參見(jiàn) KKScrollView 的實(shí)現(xiàn),當(dāng)滑動(dòng)手勢(shì)結(jié)束時(shí),根據(jù)結(jié)束的加速度,給衰減動(dòng)畫(huà)一個(gè)初始的velocity,用來(lái)決定衰減的時(shí)長(zhǎng)。
4)POPCustomAnimation
通過(guò)自定義block刷新動(dòng)畫(huà)幀,更靈活的方式
POPCustomAnimation 并不是基于POPPropertyAnimation的,它直接繼承自PopAnimation用于創(chuàng)建自定義動(dòng)畫(huà)用的,通過(guò)POPCustomAnimationBlock類型的block進(jìn)行初始化,
typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation);
此block會(huì)在界面的每一幀更新的時(shí)候被調(diào)用,創(chuàng)建者需要在block中根據(jù)當(dāng)前currentTime和elapsedTime來(lái)決定如何更新target的相關(guān)屬性,以實(shí)現(xiàn)特定的動(dòng)畫(huà)。當(dāng)你需要結(jié)束動(dòng)畫(huà)的時(shí)候就在block中返回NO,否則返回YES。
詳情見(jiàn)
facebook-pop-sample
&&POP-Handapp