經(jīng)過(guò)幾次實(shí)驗(yàn),發(fā)現(xiàn)如果分享的文章能構(gòu)成系列,效果會(huì)非常好。同時(shí)自己也能收獲很大,能夠整塊整塊的復(fù)習(xí),也能夠幫助自己更深入的塊狀學(xué)習(xí)知識(shí)。對(duì)自己梳理線條,整理知識(shí)體系作用非常大。
所以這次還是打算用這種方式,一起來(lái)分享一下iOS中關(guān)于動(dòng)畫的部分。iOS 的動(dòng)畫渲染簡(jiǎn)直是帥的不要不要的,哈哈。其實(shí)當(dāng)初就是因?yàn)閕OS的動(dòng)畫,還有iOS的對(duì)手勢(shì)的處理深深的打動(dòng)了我,才讓我這樣一個(gè)高齡中年老男人開(kāi)始了iOS這條路。啦啦啦啦~
動(dòng)畫這個(gè)系列大概會(huì)分享五篇文章,但是也有可能因?yàn)樽约和祽谢蛘咂渌壒矢淖円幌?。Hoho~
-----------------------華麗分割線,iOS動(dòng)畫系列全集鏈接-------------------------------------------------
第一篇:iOS動(dòng)畫系列之一:通過(guò)實(shí)戰(zhàn)學(xué)習(xí)CALayer和透視的原理。做一個(gè)帶時(shí)分秒指針的時(shí)鐘動(dòng)畫(上)
第二篇:iOS動(dòng)畫系列之二:通過(guò)實(shí)戰(zhàn)學(xué)習(xí)CALayer和透視的原理。做一個(gè)帶時(shí)分秒指針的時(shí)鐘動(dòng)畫。包含了OC和Swift兩種源代碼(下)
第三篇:iOS動(dòng)畫系列之三:Core Animation。介紹了Core Animation的常用屬性和方法。
第四篇:CABasic Animation。iOS動(dòng)畫系列之四:基礎(chǔ)動(dòng)畫之平移篇
第五篇:CABasic Animation。iOS動(dòng)畫系列之五:基礎(chǔ)動(dòng)畫之縮放篇&旋轉(zhuǎn)篇
第六篇:iOS動(dòng)畫系列之六:利用CABasic Animation完成帶動(dòng)畫特效的登錄界面
第七篇:iOS動(dòng)畫系列之七:實(shí)現(xiàn)類似Twitter的啟動(dòng)動(dòng)畫
第八篇:iOS動(dòng)畫系列之八:使用CAShapeLayer繪畫動(dòng)態(tài)流量圖
第九篇:iOS動(dòng)畫系列之九:實(shí)現(xiàn)點(diǎn)贊的動(dòng)畫及播放起伏指示器
第十篇:實(shí)戰(zhàn)系列:繪制過(guò)山車場(chǎng)景
開(kāi)始咱們的第一篇內(nèi)容。
1. 最終實(shí)現(xiàn)的效果以及思維導(dǎo)圖
實(shí)現(xiàn)的效果。不小心暴露了寫文章的時(shí)間。-_-+++

實(shí)現(xiàn)的步驟思維導(dǎo)圖:

2. CALayer
其實(shí)今天分享的主角是CALayer。因?yàn)樗械膭?dòng)畫都是在CALayer上完成的。
- 在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,retain) CALayer *layer; - 當(dāng)UIView需要顯示到屏幕上時(shí),會(huì)調(diào)用drawRect:方法進(jìn)行繪圖,并且會(huì)將所有內(nèi)容繪制在自己的圖層上,繪圖完畢后,系統(tǒng)會(huì)將圖層拷貝到屏幕上,于是就完成了UIView的顯示
- 換句話說(shuō),UIView本身不具備顯示的功能,是它內(nèi)部的層才有顯示功能
2.1 CALayer的基本屬性
屬性類型|屬性名稱|用途
-------|---------
@property CGFloat |borderWidth;|邊寬
@property CGColorRef |borderColor;|邊的顏色
@property CGColorRef |backgroundColor;| 背景顏色
@property float |opacity;|透明度
@property CGColorRef |shadowColor;| 陰影顏色
@property float |shadowOpacity;|陰影透明度,設(shè)置范圍0~1。
@property CGSize |shadowOffset;|陰影的偏移
@property CGFloat |shadowRadius;|陰影的模糊度
@property(strong) id |contents;|內(nèi)容??梢栽O(shè)置為圖片,但是需要橋接。
@property CGFloat| cornerRadius;|圓角
@property CGRect |bounds;| Layer的大小
@property CGPoint |position;| 默認(rèn)情況下相當(dāng)于UIView的center
@property CGPoint |anchorPoint;| position的錨點(diǎn)
@property CATransform3D |transform;| 用來(lái)做形變的,是一個(gè)矩陣??梢岳斫鉃榻Y(jié)構(gòu)體。
@property BOOL |masksToBounds;|超過(guò)部分進(jìn)行裁剪
- 設(shè)置陰影的時(shí)候,陰影顏色+陰影偏移(或者陰影路徑)+陰影透明度缺一不可。
- 陰影模糊度如果不設(shè)置,默認(rèn)值就是3.0000。
- 陰影的路徑:
- 設(shè)置了陰影的路徑,就不再需要設(shè)置陰影的偏移量了。
- 設(shè)置了陰影的路徑之后,也不能再設(shè)置
masksToBounds。因?yàn)槌^(guò)部分會(huì)被裁減。
以實(shí)現(xiàn)下圖為例:

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:imageView];
// 設(shè)置背景顏色。注意UIColor 和 CGColor之間的互換
imageView.layer.backgroundColor = [UIColor grayColor].CGColor;
// 生成一個(gè)path
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(-10, -10, imageView.bounds.size.width + 20, imageView.bounds.size.height + 20)];
// 設(shè)置陰影path
imageView.layer.shadowPath = path.CGPath;
// 設(shè)置陰影顏色
imageView.layer.shadowColor = [UIColor lightGrayColor].CGColor;
// 設(shè)置陰影透明度
imageView.layer.shadowOpacity = 0.5;
2.2 手動(dòng)創(chuàng)建一個(gè)CALayer
- 創(chuàng)建CALayer
- 在設(shè)置frame的時(shí)候,內(nèi)部同時(shí)設(shè)置了position,bounds.size 都會(huì)發(fā)生改變。
- 設(shè)置position,就和設(shè)置UIView的center一樣的。
- 記得要添加到父CALayer上。
CALayer *layer = [[CALayer alloc] init];
// ------------------- 設(shè)置位置大小 ---------------------
// 方式一: 直接設(shè)置 frame
// layer.frame = CGRectMake(50, 50, 200, 200);
// 方式二:
// 先設(shè)置大小
layer.bounds = CGRectMake(0, 0, 100, 100);
// 再設(shè)置位置(默認(rèn)情況下 position 指的是 center。)
layer.position = CGPointMake(150, 150);
// ------------------- 設(shè)置位置大小 ---------------------
layer.backgroundColor = [UIColor redColor].CGColor;
layer.opacity = 0.7;
[self.view.layer addSublayer:layer];
}
2.3 transform
從這里開(kāi)始,咱們的坐標(biāo)軸就變成了xyz三個(gè)軸向了,因?yàn)閳D案也會(huì)變成立體的了。
- 從 layer 的中心點(diǎn)到 給定的坐標(biāo)點(diǎn)之間連一條線, 然后以這個(gè)線為中心軸, 開(kāi)始旋轉(zhuǎn)
self.myLayer.transform = CATransform3DMakeRotation(M_PI_4, 10, 20, 30);
這段代碼的意思就是說(shuō)從{0,0,0}這個(gè)點(diǎn),到{10,20,30}這個(gè)點(diǎn),劃一根線。圖形繞著這根線,旋轉(zhuǎn)M_PI_4度數(shù)。
2.3.1 修改透視
在真實(shí)世界中,當(dāng)物體遠(yuǎn)離我們的時(shí)候,由于視角的原因看起來(lái)會(huì)變小,理論上說(shuō)遠(yuǎn)離我們的視圖的邊要比靠近視角的邊跟短,但實(shí)際上并沒(méi)有發(fā)生,而我們當(dāng)前的視角是等距離的,也就是在3D變換中任然保持平行,和之前提到的仿射變換類似。
“為了做一些修正,我們需要引入投影變換(又稱作z變換)來(lái)對(duì)除了旋轉(zhuǎn)之外的變換矩陣做一些修改,Core Animation并沒(méi)有給我們提供設(shè)置透視變換的函數(shù),因此我們需要手動(dòng)修改矩陣值,幸運(yùn)的是,很簡(jiǎn)單:
CATransform3D的透視效果通過(guò)一個(gè)矩陣中一個(gè)很簡(jiǎn)單的元素來(lái)控制:m34。m34用于按比例縮放X和Y的值來(lái)計(jì)算到底要離視角多遠(yuǎn)?!?/p>
*Excerpt From: 鐘聲. “ios核心動(dòng)畫高級(jí)技巧.” iBooks. *

- 通過(guò)修改transform的m34來(lái)達(dá)到效果
- transform可以看成是一個(gè)結(jié)構(gòu)體,所以修改的時(shí)候需要通過(guò)一個(gè)中間量才能修改。
- m34的默認(rèn)值是0,可以通過(guò)設(shè)置m34為-1.0 /
d來(lái)應(yīng)用透視效果 -
d代表了想象中視角相機(jī)和屏幕之間的距離,以像素為單位,那應(yīng)該如何計(jì)算這個(gè)距離呢?實(shí)際上并不需要,大概估算一個(gè)就好了?!?/li> - “因?yàn)橐暯窍鄼C(jī)實(shí)際上并不存在,所以可以根據(jù)屏幕上的顯示效果自由決定它的防止的位置。通常500-1000就已經(jīng)很好了”
Excerpt From: 鐘聲. “ios核心動(dòng)畫高級(jí)技巧.” iBooks.
struct CATransform3D{
CGFloat m11(x縮放), m12(y切變), m13(旋轉(zhuǎn)), m14();
CGFloat m21(x切變), m22(y縮放), m23, m24;
CGFloat m31(旋轉(zhuǎn)), m32, m33, m34(透視效果,要有旋轉(zhuǎn)角度才能看出效果);
CGFloat m41(x平移), m42(y平移), m43(z平移), m44;
};
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
// 定義矩陣
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0 / 800;
// 旋轉(zhuǎn)加透視
transform = CATransform3DRotate(transform, -M_PI_4, 0, 1, 0);
imageView.layer.transform = transform;
2.3.2 縮放
//方式一:
transform = CATransform3DMakeScale(<#CGFloat sx#>, <#CGFloat sy#>, <#CGFloat sz#>)
//方式二:
transform = CATransform3DScale(imageView.layer.transform, <#CGFloat sx#>, <#CGFloat sy#>, <#CGFloat sz#>)
2.4 重要屬性之position和anchorPoint
- 默認(rèn)情況下position相當(dāng)于UIView 的center
- position決定了layer在父上的位置。
- 但是anchorPoint決定了position在自身的位置。
- anchorPoint的數(shù)值只能是0~1。所以是按照百分比計(jì)算的。
3. 隱式動(dòng)畫
- 當(dāng)對(duì)非Root Layer的部分屬性進(jìn)行修改時(shí),默認(rèn)會(huì)自動(dòng)產(chǎn)生一些動(dòng)畫效果
- 所有的非Root Layer,也就是手動(dòng)創(chuàng)建的CALayer對(duì)象,都存在著隱式動(dòng)畫
- 所有注釋里面寫著有Animatable,這個(gè)屬性就有隱式動(dòng)畫效果。

3.1 幾個(gè)常見(jiàn)的Animatable Properties:
- bounds:用于設(shè)置CALayer的寬度和高度。修改這個(gè)屬性會(huì)產(chǎn)生縮放動(dòng)畫
- backgroundColor:用于設(shè)置CALayer的背景色。修改這個(gè)屬性會(huì)產(chǎn)生背景色的漸變動(dòng)畫
- position:用于設(shè)置CALayer的位置。修改這個(gè)屬性會(huì)產(chǎn)生平移動(dòng)畫
3.2 關(guān)閉隱式動(dòng)畫
- 可以通過(guò)動(dòng)畫事務(wù)(CATransaction)關(guān)閉默認(rèn)的隱式動(dòng)畫效果
- 關(guān)閉或者修改隱式動(dòng)畫的步驟:
- 開(kāi)啟動(dòng)畫事物
- 關(guān)閉動(dòng)畫效果或者修改動(dòng)畫事件
- 設(shè)置動(dòng)畫完成后的動(dòng)作(可以不設(shè)置)
- 修改屬性
- 提交
//開(kāi)啟
[CATransaction begin];
//關(guān)閉動(dòng)畫
[CATransaction setDisableActions:YES];
//修改屬性
self.myview.layer.position = CGPointMake(10, 10);
//提交
[CATransaction commit];
寶貝兒們,我錯(cuò)了。寫到這里發(fā)現(xiàn)已經(jīng)辣么長(zhǎng)辣么長(zhǎng)了,再寫下去這篇該沒(méi)有人看了。
那么,那么。。。。就臨時(shí)變卦吧,把這篇文章變成上下集吧。哈哈~就這么愉快的自己打自己的臉了,文章開(kāi)始還說(shuō)要五篇~
所以,證明一個(gè)道理。計(jì)劃都只是用來(lái)計(jì)劃的,樹(shù)立一個(gè)目標(biāo),能不能實(shí)現(xiàn)再說(shuō)。哈哈~