粉骨碎身全不怕, 要留清白在人間!<小拳石>
基礎(chǔ)知識:
iOS能夠?qū)崿F(xiàn)動畫的方式:(如上圖)
- UIView基礎(chǔ)實(shí)現(xiàn)方式一
- UIView基礎(chǔ)實(shí)現(xiàn)方式二
- CoreAnimation實(shí)現(xiàn)方式
動畫的效果簡述:
- 傳達(dá)狀態(tài)
- 提高用戶對直接操作的感知
- 幫助用戶可視化操作的結(jié)果
UIVIew 的基礎(chǔ)動畫:
- UIKit直接將動畫繼承到UIView類中, 當(dāng)內(nèi)部的一些屬性發(fā)生改變時, UIView將為這些改變提供動畫支持.
- 執(zhí)行動畫的工作由UIView類自動完成, 但希望在執(zhí)行動畫時通知視圖, 為此需要將改變屬性的代碼放在
[UIView beginAnimations: nil context: nil]
和[UIView commitAnimations]
之間.
代碼部分詳細(xì)介紹相關(guān)屬性
CALayer基本介紹:
- CALayer負(fù)責(zé)繪制, 提供UIView需要展示的內(nèi)容, 不能交互
- UIView負(fù)責(zé)交互,顯示CALayer繪制的內(nèi)容
- CALayer(層)是屏幕上的一個矩形區(qū)域, 在每一個UIView中都包含一個根
- CALayer, 在UIView上的所以視覺效果都是在這個Layer上進(jìn)行的.
1: 在 iOS 中, 我們能看見的, 例如按鈕, 文本, 標(biāo)簽, 輸入框, 等等 都是 UIView
2: 其實(shí) UIView 之所以能顯示在屏幕上, 完全是因為它內(nèi)部的一個圖層, 在創(chuàng)建 UIView 對象的時候, UIView 內(nèi)部會自動創(chuàng)建一個圖層就是(CALayer 對象), 通過 UIView 的 layer 屬性就可以訪問這個層
3: 當(dāng) UIView 需要顯示到屏幕上時, 會調(diào)用 drawRect: 方法進(jìn)行繪圖, 并且將所有的繪制內(nèi)容在自己的圖層上繪制, 給圖層繪制完畢后, 系統(tǒng)將會拷貝圖層到屏幕上, 完成 UIView 的顯示
4: UIVIew 本身是不具備顯示功能的, 真正擁有顯示功能的是里面的 layer 層
5: 通過 UIView 的圖層, 可以調(diào)整 UIView 的一些界面屬性, 例如陰影 圓角 邊框 顏色
CALayer外形特征主要包括:
- 層的大小尺寸
- 背景色
- 內(nèi)容(可以填充圖片或者使用Core Graphics繪制的內(nèi)容)
- 積習(xí)是否使用圓角
- 矩形是否有陰影
CALayer常用屬性:
與UIView動畫相比, CoreAnimation能夠?qū)崿F(xiàn)更多復(fù)雜, 好看, 高效的動畫效果:
- 陰影, 圓角, 帶顏色的邊框
3D變換
透明遮罩
多級非線性動畫
-
CALayer的坐標(biāo)系統(tǒng)比UIView多了一個anchorPoint屬性
anchorPoint錨點(diǎn)相對自身bounds來說,默認(rèn)值為(0.5,0.5),即是anchorPoint的默認(rèn)值在layer的中心點(diǎn),它的值在0~1之間
簡單圖示錨點(diǎn)
CoreAnimation動畫
CoreAnimation動畫位于iOS框架的Media層
CoreAnimation動畫實(shí)現(xiàn)需要添加QuartzCore.Framework
CoreAnimation基本上是Layer Animation
CABasicAnimation基本單一類型的動畫
CAKeyframeAnimation 幀動畫, 主要操作屬性與keyPath 和 values值組合
CAAnimationGroup組合動畫, 操作屬性: animations將CAAnimation類型的動畫加入數(shù)組, FIFO隊列的方式執(zhí)行
1: 核心動畫的基本概念
① core Animation, 核心動畫, 是一組非常強(qiáng)大的動畫處理 API, 可以用少量的代碼, 實(shí)現(xiàn)強(qiáng)大的功能
② core Animation, 可以用在 Mac OS 和 iOS 兩個平臺
③ core Animation, 動畫的執(zhí)行過程, 都是在后臺操作的, 所以不會阻塞主線程
④ core Animation, 是直接操作 CALayer 層的, 并不是 UIView
2: CAAnimation
① 所有動畫的父類, 負(fù)責(zé)控制動畫的持續(xù)時間和速度, 他是一個抽象的類, 不能直接使用, 應(yīng)該使用他的子類
② 屬性說明:
- duration: 動畫的持續(xù)時間
- repeatCount: 動畫的重復(fù)次數(shù)
- repeatDuration: 重復(fù)時間
- removeOnCompletion (BOOL): 默認(rèn)為 YES, 表示動畫執(zhí)行完畢后就從圖層上移除, 圖形會恢復(fù)到執(zhí)行之前的狀態(tài). 如果想要保持執(zhí)行之后的狀態(tài), 那就設(shè)置 NO, 但是, 還需要設(shè)置 fillMode 值為 kCAFillModeForwards
- fillModel: 決定當(dāng)前對象在非活動的時間段的行為, 比如動畫開始前或者動畫結(jié)束之后 (想要 fillMode 有效, 最好將removeOnCompletion = 0);
- kCAFillModeRemove:
默認(rèn)值也就是當(dāng)前動畫開始前和動畫結(jié)束后, 動畫對 layer 都沒有影響, 動畫結(jié)束后, layer 會恢復(fù)之前的狀態(tài)
- kCAFillModeForwards:
當(dāng)前結(jié)束動畫后, layer 會一直保持最后的狀態(tài) - kCAFillModeBackwards:
在動畫開始之前, 只需要將動畫加入一個 layer, layer 便立即進(jìn)入動畫的初始狀態(tài)并等待動畫的開始. - kCAFillModeBoth: 就是上面兩個 kCAFillModeForwards 和kCAFillModeBackwards 的合成
- beginTime: 可以用來設(shè)置動畫的延遲時間, 若想設(shè)置延遲 2秒, 那么就設(shè)置 CACurrentMediaTime() + 2 CACurrentMediaTime()圖層當(dāng)前的時間
- timeFuncation: 速度控制函數(shù) 控制動畫運(yùn)行的節(jié)奏
---> CAMediaTimingFunctionLinear (線性): 勻速, 給你一個相對靜態(tài)的感覺
---> CAMediaTimingFunctionEaseIn (淡入): 動畫緩慢進(jìn)入, 然后加速離開
---> CAMediaTimingFunctionEaseOut (淡出): 動畫全速進(jìn)入, 然后減速到達(dá)目的地
---> CAMediaTimingFunctionEaseInEaseOut (淡入淡出)
③ CAAnimation 的子類
- CABasicAnimation
- CALeyFrameAnimation
- CAAnimationGroup
- CASpringAnimation
④ 屬性說明
- keypath: 通過制定 CALayer 的一個屬性名稱為 keypath(NSString 類型) , 并且對 CALayer 這個屬性值進(jìn)行修改, 達(dá)到相應(yīng)的動畫效果, 比如, 制定@"postion"為 keypath , 就相當(dāng)于修改了 CALayer 的 poison 屬性的值,達(dá)到平移的動畫效果.
- 下面的代碼部分會對這個 關(guān)建路徑支持結(jié)構(gòu)字段 進(jìn)行相應(yīng)的總結(jié)
- 關(guān)鍵路徑支持的部分字段補(bǔ)充說明
margin = 布局
zPosition = 翻轉(zhuǎn)
backgroundColor = 背景顏色
cornerRadius = 圓角
borderWidth = 邊框?qū)?br> bounds = 大小
contents = 內(nèi)容
contentsRect = 內(nèi)容大小
cornerRadius = 圓角
frame = 大小位置
hidden = 顯示隱藏
mask 遮罩
masksToBounds
opacity 不透明的
position 位置
shadowColor 陰影顏色
shadowOffset 陰影偏移量
shadowOpacity 陰影不透明的
shadowRadius 陰影半徑
transform.scale = 比例轉(zhuǎn)換
transform.scale.x =以 x軸 比例轉(zhuǎn)換
transform.scale.y = 以 y軸 比例轉(zhuǎn)換
transform.rotation.z = 平面圓形旋轉(zhuǎn)
3: 關(guān)鍵幀動畫 與 CABasicAnimation 的區(qū)別
① CABasicAnimation只能從一個數(shù)值(fromvalue) 變換到另外一個數(shù)值 (tovaule)
② 關(guān)鍵幀動畫, 會使用一個 NSArray 保存這些數(shù)值
4: 動畫組
① 屬性說明:
- animations: 用來保存一組動畫對象NSArray
- 默認(rèn)情況下, 一組動畫對象是同時運(yùn)動的, 也可以通過設(shè)置動畫的 beginTime 屬性來更改動畫的開始時間
5: 轉(zhuǎn)場動畫 -------- CATransition: --------------
CATransition: 用于做轉(zhuǎn)場動畫效果, 能夠為 layer 層提供移出屏幕和移入屏幕的動畫效果
① 動畫屬性:
- type: 動畫的過渡效果
類型字符串 效果說明
fade 交叉淡化過渡
push 新視圖把舊視圖推出去
moveIn 新視圖移到舊視圖上面
reveal 將舊視圖移開,顯示下面的新視圖
cube 立方體翻轉(zhuǎn)效果
oglFlip 上下左右翻轉(zhuǎn)效果
suckEffect 收縮效果,像一塊布被抽走
rippleEffect 水滴效果
pageCurl 向上翻頁效果
pageUnCurl 向下翻頁效果
cameraIrisHollowOpen 相機(jī)鏡頭打開效果
cameraIrisHollowClose 相機(jī)鏡頭關(guān)閉效果
- subtype: 動畫的過渡方向
- startProgress: 動畫的起點(diǎn)(在整個動畫的百分比)
- endProgress: 動畫的終點(diǎn)
UIView 的基礎(chǔ)動畫 代碼總結(jié)
實(shí)例1: 自定義一個屬性 MyLabel (UILabel)類型的 展示的是 UIView 的動畫效果, 在一個觸發(fā)方法里面實(shí)現(xiàn)動畫,我這里寫在 TouchBegin 里面.
//1. 創(chuàng)建一個動畫
[UIView beginAnimations:nil context:nil];
//2. 動畫延遲設(shè)置
[UIView setAnimationDelay:1];
//3. 給動畫添加代理(不遵循代理協(xié)議, 也能實(shí)現(xiàn)代理方法)
[UIView setAnimationDelegate:self];
//4. 給動畫添加方法(動畫結(jié)束后執(zhí)行)
[UIView setAnimationDidStopSelector:@selector(stopAc)];
//5. 動畫持續(xù)時間(完成動畫所需時間)
[UIView setAnimationDuration:2];
//6. 設(shè)置動畫是否會做一次反向的執(zhí)行 (等會屬性里面再說)
[UIView setAnimationRepeatAutoreverses:YES];
//7. 設(shè)置動畫移動的新位置
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
//8. 開始提交動畫 (解釋可以看下面)
[UIView commitAnimations];
總結(jié)一下這里涉及的方法: 均是 UIView 的類方法
- 第 1個方法: 動畫馬上開始:begin
+(void)beginAnimations:(NSString*)animationID context:(void *)context{}
# 參數(shù)1: animationID 作為動畫的標(biāo)示使用, 可以方便移除動畫操作
# 參數(shù)2: context 動畫的設(shè)置 自定義的一些動畫數(shù)據(jù),這些數(shù)據(jù)將發(fā)送給動畫的代理方法 默認(rèn) nil
- 最后 1 個方法: commit
# 這個方法 就是提交動畫 也是標(biāo)記動畫的內(nèi)容已經(jīng)編輯好了 可以使用效果了
+ (void)commitAnimations
在這兩個方法之間就我們進(jìn)行,動畫相關(guān)的一些設(shè)置,下面是一些設(shè)置的方法
# 設(shè)置代理 及其 方法不需要設(shè)置遵循代理方法 默認(rèn) nil 沒有代理
+ (void)setAnimationDelegate:(nullable id)delegate;
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;
# 設(shè)置動畫持續(xù)時間 默認(rèn) = 0.2
+ (void)setAnimationDuration:(NSTimeInterval)duration;
# 設(shè)置動畫的延遲時間 默認(rèn)是不延遲 就是0.00
+ (void)setAnimationDelay:(NSTimeInterval)delay;
# 設(shè)置動畫的開始時間 default = now ([NSDate date])
+ (void)setAnimationStartDate:(NSDate *)startDate;
# 設(shè)置動畫的曲線方式(動畫的總體變化的時間曲線:開始快最后慢,開始慢最后快,最后慢,均勻線性) 默認(rèn)default = UIViewAnimationCurveEaseInOut
/*typedef NS_ENUM(NSInteger, UIViewAnimationCurve){
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear
};
*/
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;
# 動畫的重復(fù)次數(shù) default = 0.0.
+ (void)setAnimationRepeatCount:(float)repeatCount;
# 設(shè)置動畫是否做一次反向的執(zhí)行。
/*如果設(shè)置為YES:動畫將執(zhí)行:動畫初始狀態(tài)->動畫->動畫完成狀態(tài)->動畫->動畫初始狀態(tài) 。
如果設(shè)置為NO:默認(rèn)值*/
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
# 設(shè)置動畫的開始狀態(tài)
/*
YES : 第一個動畫正在 執(zhí)行時候, 另一個動畫恰好開始, 這樣第一個動畫的當(dāng)前狀態(tài), 就是另一個動畫的開始狀態(tài)
NO: 第一個達(dá)到完成狀態(tài), 下一個動畫才開始執(zhí)行動畫的效果
*/
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
# 設(shè)置視圖view的過渡效果, transition指定過渡類型, cache設(shè)置YES代表使用視圖緩存,性能較好
/*
UIView官方提供五種動畫效果供大家使用,分別為:
UIViewAnimationTransitionNone 不使用動畫
UIViewAnimationTransitionFlipFromLeft 從左向右旋轉(zhuǎn)翻頁
UIViewAnimationTransitionFlipFromRight 從右向左旋轉(zhuǎn)翻頁
UIViewAnimationTransitionCurlUp 卷曲翻頁,從下往上
UIViewAnimationTransitionCurlDown 卷曲翻頁,從上往下
*/
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
# 設(shè)置view是否有動畫效果
/*
YES: 默認(rèn)有動畫的能力
NO: 關(guān)閉動畫效果
效果關(guān)閉并不會對 UI 的改變有什么影響只是不會 "動畫" 了而已, 其他的大小什么屬性依然有效的
*/
+ (void)setAnimationsEnabled:(BOOL)enabled;
# 判斷當(dāng)前的動畫效果是否關(guān)閉了
+ (BOOL)areAnimationsEnabled;
通過 UIView 的幾個 Block 方法進(jìn)行動畫設(shè)置
- // 實(shí)現(xiàn)動畫 的 Block1
參數(shù)1 : Duration 動畫持續(xù)時間 Block 里面就寫你要實(shí)現(xiàn)的效果(位置的改變等)
[UIView animateWithDuration:2 animations:^{
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
}];
- // 實(shí)現(xiàn)動畫 的 Block2
```code
# 參數(shù)比上面多一個 動畫結(jié)束后的操作
[UIView animateWithDuration:2 animations:^{
self.MyLabel.frame = CGRectMake(100, 100, 200, 200);
} completion:^(BOOL finished) {
NSLog(@"動畫結(jié)束的操作可以寫這里");
}];```
- // 實(shí)現(xiàn)動畫 的 Block3
```code
/*
參數(shù)1: Duration: 動畫持續(xù)時間
參數(shù)2: delay: 延遲時間
參數(shù)3: options: 枚舉值 動畫的效果類型*/
[UIView animateWithDuration:2 delay:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
} completion:^(BOOL finished) {
NSLog(@"結(jié)束了%d", finished);
}];```
- //實(shí)現(xiàn)動畫的Block4 彈簧效果
```code
/*
Spring: 模擬彈簧彈跳的效果
參數(shù): Damping:阻尼 0-1 阻尼越小動畫越明顯
參數(shù): initialSpringVelocity : 動畫初始變化速度
參數(shù): options 轉(zhuǎn)變的風(fēng)格 枚舉值
*/
[UIView animateWithDuration:10 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:15 options:(UIViewAnimationOptionCurveEaseInOut) animations:^{
self.MyLabel.center = CGPointMake(self.view.center.x, 100);
} completion:^(BOOL finished) {
NSLog(@"彈簧效果結(jié)束");
}];```
- //實(shí)現(xiàn)動畫的Block5 關(guān)鍵幀動畫 也就是里面有好幾個動畫進(jìn)行轉(zhuǎn)變
```code
/*
Duration:持續(xù)時間
delay: 延遲時間
options: 枚舉值 動畫的風(fēng)格
*/
[UIView animateKeyframesWithDuration:3 delay:0 options:(UIViewKeyframeAnimationOptionRepeat) animations:^{
/*
參數(shù)1: RelativeStartTime: 相對的開始時間
參數(shù)2: relativeDuration:相對持續(xù)時間
*/
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.5 animations:^{
self.MyLabel.center = self.view.center;
}];
[UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.3 animations:^{
self.MyLabel.frame = CGRectMake(100, 100, 100, 100);
}];
[UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.3 animations:^{
self.MyLabel.frame = CGRectMake(100, 400, 100, 100);
}];
} completion:^(BOOL finished) {
NSLog(@"結(jié)束了");
}];
- CAAnimation 的子類
------------ CABasicAnimation -----------------
# 1: 創(chuàng)建 以字段為 旋轉(zhuǎn)變換
CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
# 動畫效果的初始值
basic.fromValue = @0;
# 動畫效果變化的結(jié)束值 (絕對值) 這里就是旋轉(zhuǎn)的角度從多少轉(zhuǎn)到多少度
basic.toValue = @(2*M_PI);
# 動畫執(zhí)行時間
basic.duration = 5;
# Layer 動畫需要天加到 layer 上 forkey 我們可以寫上我們標(biāo)記的動畫屬性
[self.MyLabel.layer addAnimation:basic forKey:@"transform.rotation"];
--------- CAKeyFramAnimation 關(guān)鍵幀動畫--------
// 創(chuàng)建 以關(guān)鍵字段 位置變化
CAKeyframeAnimation *keyframe = [CAKeyframeAnimation animationWithKeyPath:@"position"];
// 建幾個動畫的位置
CGPoint p1 = CGPointMake(0, 0);
CGPoint p2 = CGPointMake(0, 400);
CGPoint p3 = CGPointMake(400, 100);
CGPoint p4 = CGPointMake(100, 200);
CGPoint p5 = CGPointMake(200, 300);
NSValue *v1 = [NSValue valueWithCGPoint:p1];
NSValue *v2 = [NSValue valueWithCGPoint:p2];
NSValue *v3 = [NSValue valueWithCGPoint:p3];
NSValue *v4 = [NSValue valueWithCGPoint:p4];
NSValue *v5 = [NSValue valueWithCGPoint:p5];
//屬性 values : 數(shù)組對象 里面的元素稱為"keyFrame"(關(guān)鍵幀), 動畫對象會在指定的時間里 (duration). 依次顯示values 數(shù)組中的每一個關(guān)鍵幀
keyframe.values = @[v1,v2,v3,v4,v5];
keyframe.duration = 10;
// 每一幀的時間, 每一幀的時間為比例的累加計算 取值范圍 0-1,沒有設(shè)置的話 每一幀的時間是平分的
keyframe.keyTimes = @[@0.1,@0.1,@0.1,@0.1];
[self.MyLabel.layer addAnimation:keyframe forKey:@"系統(tǒng)保留關(guān)鍵字"];
--------- CAAnimationGroup 動畫組--------
// 創(chuàng)建
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 10;
// 把上面兩個動畫加到這個動畫組里面
group.animations = @[basic,keyframe];
[self.MyLabel.layer addAnimation:group forKey:@"同上"];
--------------- CASpringAnimation 模擬彈簧動畫效果--------
// 創(chuàng)建一個彈簧動畫 結(jié)構(gòu)關(guān)鍵字段 意思是豎直方向上 模擬彈簧
CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:@"position.y"];
// 設(shè)置動畫效果的初始值
spring.fromValue = @50;
// 設(shè)置動畫的結(jié)束值
spring.toValue = @10;
// 阻尼系數(shù)
spring.damping = 0.1;
// 剛度系數(shù): (勁度系數(shù) / 彈性系數(shù)): 系數(shù)越大,形變的產(chǎn)生的力越大, 運(yùn)動越快
spring.stiffness = 10;
// 質(zhì)量: 影響圖層運(yùn)動時候的慣性, 質(zhì)量越大彈簧拉伸和壓縮的幅度越大 (動畫的幅度,波動變大)
spring.mass = 1;
// 初識速率: 動畫視圖的初識速度大小
// 速率為正時候, 速度方向與運(yùn)動方向一致, 否則相仿.
spring.initialVelocity = 1;
// settlingDuration 結(jié)算時間,預(yù)估彈簧動畫到停住的時間的估算, 根據(jù)當(dāng)前動畫的各個參數(shù)估算, 通常彈簧動畫的估算時間使用結(jié)算時間比較準(zhǔn)確
spring.duration = spring.settlingDuration;
[self.MyLabel.layer addAnimation:spring forKey:@"彈簧"];
---------- CATransition -------
// 創(chuàng)建
CATransition *trans = [CATransition animation];
// 效果
trans.type = @"pageCurl";
// 開始位置 (0-1)
trans.startProgress = 0;
// 結(jié)束位置 (0-1)
trans.endProgress = 1;
// 效果方向
trans.subtype = kCATransitionFromLeft;
// 重復(fù)次數(shù)
trans.repeatCount = 10;
// 持續(xù)時間
trans.duration = 3;
[self.MyView.layer addAnimation:trans forKey:@"11"];