Core Animation相關內容基本介紹
此框架把屏幕上的內容組合起來,這個內容被分解成圖層,放到圖層樹中,這個樹形成了你能在應用程序看到的內容的基礎
圖層在iOS中就是CALayer類
當我們創(chuàng)建一個UIView類的時候就會同時創(chuàng)建這個類的layer屬性。 而UIView和CALayer分工明確。
UIView類確切的知道響應鏈,可以響應事件。
UIView封裝了CALayer的部分功能。比如UIView中的frame、center屬性對應CALayer中的frame、position。
UIView還封裝了高級API使動畫更簡單。
UIView還具有自動排版、布局的功能
CALayer是UIView的內部實現(xiàn)細節(jié),真正負責屏幕上的顯示和動畫。
CALayer的部分屬性并沒有被UIView暴露。比如:
~ 陰影、圓角、帶顏色的邊框
~ 3D變換(后面會講到UIView只可以做仿射變換)
~ 透明遮罩
最好使用使用視圖而不是單獨的圖層的原因之一有:視圖可以進行自動布局,自適應屏幕的翻轉。而圖層是做不到這樣的
對于何時使用CALayer??梢詤⒖既缦聴l件:
UIView提供的動畫方案不能滿足你的要求需要使用
UIView沒有暴露的CALayer的屬性使用CALayer的特定子類,提高應用性能(后面會講到
CAShaperLayer、CATiledLayer等等)
在講解Core Animation之前需要先講講一些基礎知識
1. iOS中使用的坐標系統(tǒng):
- 點 —— @1、@2、@3分別代表每個點1個、2個、3個像素。是為了在retain設備和普通設備上有同樣的顯示效果
- 像素 —— UIImage可以指定點度量大小,是一種分辨率解決方案。而CGImage則會使用像素
-
單位 —— 類似于{0,0,1,1}。比如
anchorPoint。是相對值,而不是絕對值。即使大小改變,也不用調整
2. CALayer設置contents屬性
※ contentsGravity
※ contentsScale
※ contentsRect
※ contentsCenter
在開發(fā)中蘋果建議在UIView中不要實現(xiàn)一個空的drawRect:方法。這是因為實現(xiàn)這個方法的View會生成一個寄宿圖。這個寄宿圖就是CALayer的contents屬性。
contentsGravity是控制內容在邊界內如何對齊。對應UIView中的contentMode屬性??蛇x的類型就是top、left、right、center、aspect、fill 等等。contentsScale就是表明寄宿圖圖片的精度大小。1.0就是每個點繪制一個像素。2.0就是每個點繪制兩個像素。就是retain屏幕。
tip:contentsGravity設置的選項是沒有拉伸圖片的話,這個屬性的設置才會有顯而易見的效果。
contentsRect使用的是單位坐標。指定一個矩形,范圍外的圖片會被裁剪。然后用矩形內的內容進行填充contentsCenter使用的是單位坐標。定義了一個固定的邊框和一個在圖層上可拉伸的區(qū)域。
例如:設置為{0.25,0.25,0.5,0.5},那么圖層的四個邊角的內容不變,而其他區(qū)域內容在圖層大?。ㄓ蒫ontentsGravity決定)改變的時候就可拉伸。
3. 圖層幾何學
布局
-
frame代表了圖層的外部坐標(在父圖層上占用的空間),bounds是內部坐標,center和position代表了本圖層的anchorPoint在父圖層的位置
-
錨點
anchorPoint使用的是單位坐標,默認值為{0.5,0.5}.初始化
frame為{0,0,100,100},則position初始化為{0,0,50,50},如果改變anchorPoint的值為{0,0},則圖層左上角為錨點,左上角的點就在position的位置 -
frame的值和bounds、position和transform密切相關。改變其中一個值同時會改變其他的值。當圖層進行transform旋轉之后,frame代表的區(qū)域是整個軸對齊的區(qū)域
--
坐標系
- 一個圖層的
position依賴于它的父圖層的bounds。如果父圖層發(fā)生移動,子圖層也會跟著移動
- scrollView就是通過改變view的
bounds來實現(xiàn)內容滾動的效果
- 和UIView嚴格的二維坐標不同的是,CALayer存在于一個三維空間中。除了x軸和y軸,還有一個z軸的存在。有兩個屬性可以描述在z軸的位置
zPosition和anchorPointZ
-
通過增加圖層的
zPosition,就可以把圖層前置,到達小于它的zPosition值的圖層的前面。zPosition只能改變顯示順序,不能改變響應順序。響應順序還是按照addSubLayer的順序
可能會用到的API
- 坐標系的轉換:
把一個圖層坐標系下的點或矩形裝換成另一個圖層或坐標系的點
- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
- CALayer判斷點的位置
//接受一個在本圖層坐標系下的點,如果這個點在圖層范圍內就返回YES
- (BOOL)containsPoint:(CGPoint)p;
//返回能接收這個點的最遠CALayer子代。如果這個點在最外面圖層的范圍之外,則返回nil
//如果設置了zPosition,返回的就不一定是最前方的Layer
- (CALayer *)hitTest:(CGPoint)p;
4. 視覺效果屬性
× 圓角cornerRadius
- 只影響圖層背景色
-
maskToBounds會依此屬性截取 - 統(tǒng)一控制所有的角
× 圖層邊框borderColor、borderWidth
- 沿著圖層
bounds繪制,在所有子圖層之前 - 跟隨圖層的
bounds變化,而不是圖層內容
× 陰影shadowOffset、shadowColor
-
shadowOffset是CGSize類型的值。寬度控制橫向的移動,高度控制縱向的移動
shadowRadius屬性控制著陰影的模糊度,數(shù)值越大越模糊和自然shadowPath是CGPathRef類型。單獨于圖層形狀之外指定陰影的形狀
與直接指定
shadowPath相比,圖層的陰影根據(jù)圖層內容動態(tài)計算陰影的形狀。比較消耗性能
因為圖層的陰影總是在圖層范圍外,所以直接使用
maskToBounds的時候會把陰影給裁剪掉。
一、可以添加一個專門顯示陰影的圖層來得到maskToBounds+shadow的效果
二、指定shadowPath
× 圖層蒙版mask屬性 —— 是一個CALayer類型,定義了父圖層的部分可見區(qū)域。
mask圖層最重要的是它的輪廓,賦值了mask屬性,就會按照mask圖層的形狀把父視圖進行切割,保留mask圖層內的父視圖內容,舍棄圖層外的父視圖內容
× 拉伸過濾Filter —— 當圖片需要顯示不同大小的時候,拉伸過濾的算法就起到作用了。CALayer有三種過濾算法
- kCAFilterLinear
- kCAFilterNearest
- kCAFilterTrilinear
默認的過濾算法為linear,trilinear比 linear能夠更好的支持大圖;對于比較小的圖或者是差異特別明顯,極少斜線的大圖,使用Neareset可以呈現(xiàn)更好的效果。
× 組透明GroupOpacity——整個圖層樹有一個整體的透明效果還是進行透明度的混合疊加
- iOS7之后默認為YES
× 光柵化shouldRasterize —— YES代表圖層及其子圖層會被整合成一個整體的圖片
-
使用了
shouldRasterize,就要同步設置rasterizationScale來匹配屏幕layer.rasterizationScale = [UIScreen mainScreen].scale;
5. 變換
→ 仿射變換affineTransform:
是`CGAffineTransform`類型。`Core Graphics`框架對象。提供如下函數(shù)創(chuàng)建:
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
使用如下函數(shù),初始化生成一個什么都不做的變換,也就是創(chuàng)建一個
CGAffineTransform類型的空值,矩陣論中稱作單位矩陣
CGAffineTransformIdentity
混合兩個已經存在的變換矩陣,使用如下方法,在兩個變換的基礎上創(chuàng)建一個新的變換:
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
-
UIView可以通過transform屬性做變換,對應CALayer的affineTransform屬性tip:旋轉常量M_PI是一個弧度單位。弧度用數(shù)學常量pi的倍數(shù)表示。可以用以下公式進行弧度角度換算
#define DEGREES_TO_RADIANS(x) ((x)/180.0 *M_PI)這里要注意的是:旋轉的時候會尋找最短路徑進行旋轉。比如弧度大于pi,就會逆時針旋轉
-
混合變換 —— 使用以下函數(shù)可以在一個變換的基礎上做更深層次的變換
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle) CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy) CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)注意:變換的順序很重要,先旋轉再平移和先平移再旋轉的結果是不同的
→ 3D變換transform3D
-
CALayer的
transform屬性是CATransform3D類型,是一個4x4的矩陣,聲明如下struct CATransform3D { CGFloat m11, m12, m13, m14; CGFloat m21, m22, m23, m24; CGFloat m31, m32, m33, m34; CGFloat m41, m42, m43, m44; }; -
提供的創(chuàng)建函數(shù)
看起來和affineTransform類似,但是平移和縮放多了一個 z 參數(shù),旋轉除了弧度參數(shù),還多了x、y、z 三個參數(shù),分別代表每個方向軸的旋轉
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z) CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)z軸和x軸、y軸分別垂直,指向手機用戶為正方向.繞z軸的旋轉就等同于二維的仿射旋轉,繞x軸和y軸的旋轉就突破了二維的空間。
scale中的參數(shù)如果為負數(shù)先按軸翻轉再進行縮放
接下來就說說怎么在應用顯示擬真的3D效果 -
透視投影
為了修正視圖的遠近不同的縮放比例,我們引入
投影變換。通過修改矩陣中的m34元素控制
減少距離的值會增強透視效果,而一個非常大的值會讓它基本失去透視效果m34的默認值是0,我們可以通過設置m34為-1.0 /d來應用透視效果,d代表了想象中視角相機和屏幕之間的距離,以像素為單位。不需要計算,只需要估算一個就好了。通常500-1000就很好了。繞y軸旋轉45度并添加透視投影效果當視圖遠離觀察者的時候物體會變小變遠,當遠離到一定距離的時候,就縮成了一個點,于是視角內的所有物體都匯聚消失在了同一個點。
接下來就說說關于這個點的事
-
滅點
在現(xiàn)實中,這個點通常是物體的中點,為了在應用中創(chuàng)建擬真效果 ,這個點應該是屏幕中點,或者至少是所有3D對象的中心點
CAAnimation定義了這個點在變換圖層的anchorPoint(通常位于圖層中心,但也有例外),當圖層發(fā)生變換的時候,這個點永遠是變換之前的anchorPoint位置改變
position就改變了圖層的anchorPoint,所以為了讓所有3D視圖共用一個滅點,可以先把視圖放在屏幕中央,然后通過變換移動到指定位置幸運的是,蘋果已經幫助我們把上面這個比較繁瑣的事情封裝了
-
sublayerTransform屬性是一個
CATransform3D類型。它影響到全部子圖層。如此我們可以統(tǒng)一設置子圖層的透視變換和共享滅點。 -
其他關于3D的屬性
當把視圖繞著Y軸旋轉180度,我們就可以看到視圖的背面。繪制的就是視圖的鏡像??梢酝ㄟ^
doubleSided設置是否繪制視圖背面。扁平化圖層:
[ ] 1.繞Z軸旋轉的兩個圖層做相反的旋轉操作,第二個圖層做的旋轉會被第一個圖層旋轉抵消。
[ ] 2.而繞X軸和Y軸旋轉的不同圖層做相反的旋轉操作并不會相互抵消。
原因是盡管
Core Animation圖層存在于3D空間之內,但它們并不都存在同一個3D空間。每個圖層的3D場景其實是扁平化的,當你從正面觀察一個圖層,看到的實際上由子圖層創(chuàng)建的想象出來的3D場景至少當你用正常的CALayer的時候是這樣,CALayer有一個叫做CATransformLayer的子類可以解決這個問題
→ 固體對象
- 在應用中創(chuàng)建一個正方體,具體代碼

