iOS核心動畫(基礎篇)

Core Animation相關內容基本介紹

此框架把屏幕上的內容組合起來,這個內容被分解成圖層,放到圖層樹中,這個樹形成了你能在應用程序看到的內容的基礎

圖層在iOS中就是CALayer
當我們創(chuàng)建一個UIView類的時候就會同時創(chuàng)建這個類的layer屬性。 而UIViewCALayer分工明確。

UIView類確切的知道響應鏈,可以響應事件。
UIView封裝了CALayer的部分功能。比如UIView中的frame、center屬性對應CALayer中的frameposition。
UIView還封裝了高級API使動畫更簡單。
UIView還具有自動排版、布局的功能

CALayerUIView的內部實現(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. 圖層幾何學

布局

  1. 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的值和boundspositiontransform密切相關。改變其中一個值同時會改變其他的值。

    當圖層進行transform旋轉之后,frame代表的區(qū)域是整個軸對齊的區(qū)域


    --

坐標系

  1. 一個圖層的position依賴于它的父圖層的bounds。如果父圖層發(fā)生移動,子圖層也會跟著移動
  • scrollView就是通過改變view的bounds來實現(xiàn)內容滾動的效果
  1. 和UIView嚴格的二維坐標不同的是,CALayer存在于一個三維空間中。除了x軸和y軸,還有一個z軸的存在。有兩個屬性可以描述在z軸的位置zPositionanchorPointZ
  • 通過增加圖層的zPosition,就可以把圖層前置,到達小于它的zPosition值的圖層的前面。

    zPosition只能改變顯示順序,不能改變響應順序。響應順序還是按照addSubLayer的順序

可能會用到的API

  1. 坐標系的轉換:把一個圖層坐標系下的點或矩形裝換成另一個圖層或坐標系的點
- (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;
  1. CALayer判斷點的位置
//接受一個在本圖層坐標系下的點,如果這個點在圖層范圍內就返回YES
- (BOOL)containsPoint:(CGPoint)p;
//返回能接收這個點的最遠CALayer子代。如果這個點在最外面圖層的范圍之外,則返回nil
//如果設置了zPosition,返回的就不一定是最前方的Layer
- (CALayer *)hitTest:(CGPoint)p;
4. 視覺效果屬性

× 圓角cornerRadius

  • 只影響圖層背景色
  • maskToBounds會依此屬性截取
  • 統(tǒng)一控制所有的角

× 圖層邊框borderColorborderWidth

  • 沿著圖層bounds繪制,在所有子圖層之前
  • 跟隨圖層的bounds變化,而不是圖層內容

× 陰影shadowOffset、shadowColor

  • shadowOffsetCGSize類型的值。寬度控制橫向的移動,高度控制縱向的移動
  • shadowRadius 屬性控制著陰影的模糊度,數(shù)值越大越模糊和自然

  • shadowPathCGPathRef類型。單獨于圖層形狀之外指定陰影的形狀

與直接指定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屬性做變換,對應CALayeraffineTransform屬性

    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)建一個正方體,具體代碼

圖書地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容