iOS核心動畫(基礎篇)

Core Animation相關內容基本介紹

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

圖層在iOS中就是CALayer
當咱們建立一個UIView類的時候就會同時建立這個類的layer屬性。 而UIViewCALayer分工明確。ios

UIView類確切的知道響應鏈,能夠響應事件。
UIView封裝了CALayer的部分功能。好比UIView中的framecenter屬性對應CALayer中的frameposition
UIView還封裝了高級API使動畫更簡單。
UIView還具備自動排版、佈局的功能git

CALayerUIView的內部實現細節,真正負責屏幕上的顯示和動畫。
CALayer的部分屬性並無被UIView暴露。好比:
~ 陰影、圓角、帶顏色的邊框
~ 3D變換(後面會講到UIView只能夠作仿射變換)
~ 透明遮罩算法

最好使用使用視圖而不是單獨的圖層的緣由之一有:視圖能夠進行自動佈局,自適應屏幕的翻轉。而圖層是作不到這樣的框架

對於什麼時候使用CALayer。能夠參考以下條件:ide

  • UIView提供的動畫方案不能知足你的要求函數

  • 須要使用 UIView沒有暴露的CALayer的屬性佈局

  • 使用CALayer的特定子類,提升應用性能(後面會講到CAShaperLayerCATiledLayer等等)性能

在講解Core Animation以前須要先講講一些基礎知識

1. iOS中使用的座標系統:
  • —— @一、@二、@3分別表明每一個點1個、2個、3個像素。是爲了在retain設備和普通設備上有一樣的顯示效果
  • 像素 —— UIImage能夠指定點度量大小,是一種分辨率解決方案。而CGImage則會使用像素
  • 單位 —— 相似於{0,0,1,1}。好比anchorPoint。是相對值,而不是絕對值。即便大小改變,也不用調整
2. CALayer設置contents屬性

※ contentsGravity動畫

※ contentsScale

※ contentsRect

※ contentsCenter

在開發中蘋果建議在UIView中不要實現一個空的drawRect:方法。這是由於實現這個方法的View會生成一個寄宿圖。這個寄宿圖就是CALayer的contents屬性。

  • contentsGravity 是控制內容在邊界內如何對齊。對應UIView中的contentMode屬性。可選的類型就是top、left、right、center、aspect、fill 等等。

  • contentsScale就是代表寄宿圖圖片的精度大小。1.0就是每一個點繪製一個像素。2.0就是每一個點繪製兩個像素。就是retain屏幕。

    tip:contentsGravity設置的選項是沒有拉伸圖片的話,這個屬性的設置纔會有顯而易見的效果。

  • contentsRect使用的是單位座標。指定一個矩形,範圍外的圖片會被裁剪。而後用矩形內的內容進行填充

  • contentsCenter使用的是單位座標。定義了一個固定的邊框和一個在圖層上可拉伸的區域。

    例如:設置爲{0.25,0.25,0.5,0.5},那麼圖層的四個邊角的內容不變,而其餘區域內容在圖層大小(由contentsGravity決定)改變的時候就可拉伸。

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表明的區域是整個軸對齊的區域
    --

座標系

  1. 一個圖層的position依賴於它的父圖層的bounds。若是父圖層發生移動,子圖層也會跟着移動
  • scrollView就是經過改變view的bounds來實現內容滾動的效果
  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會依此屬性截取
  • 統一控制全部的角

× 圖層邊框borderColorborderWidth

  • 沿着圖層bounds繪製,在全部子圖層以前
  • 跟隨圖層的bounds變化,而不是圖層內容

× 陰影shadowOffsetshadowColor

  • shadowOffsetCGSize類型的值。寬度控制橫向的移動,高度控制縱向的移動

  • shadowRadius 屬性控制着陰影的模糊度,數值越大越模糊和天然

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

與直接指定shadowPath 相比,圖層的陰影根據圖層內容動態計算陰影的形狀。比較消耗性能

由於圖層的陰影老是在圖層範圍外,因此直接使用maskToBounds的時候會把陰影給裁剪掉。
1、能夠添加一個專門顯示陰影的圖層來獲得maskToBounds + shadow的效果
2、指定shadowPath

× 圖層蒙版mask屬性 —— 是一個CALayer類型,定義了父圖層的部分可見區域。

mask圖層最重要的是它的輪廓,賦值了mask屬性,就會按照mask圖層的形狀把父視圖進行切割,保留mask圖層內的父視圖內容,捨棄圖層外的父視圖內容

× 拉伸過濾Filter —— 當圖片須要顯示不一樣大小的時候,拉伸過濾的算法就起到做用了。CALayer有三種過濾算法

  • kCAFilterLinear
  • kCAFilterNearest
  • kCAFilterTrilinear

    默認的過濾算法爲linear,trilinear比 linear可以更好的支持大圖;對於比較小的圖或者是差別特別明顯,極少斜線的大圖,使用Neareset能夠呈現更好的效果。

× 組透明GroupOpacity——整個圖層樹有一個總體的透明效果仍是進行透明度的混合疊加

  • iOS7以後默認爲YES

× 光柵化shouldRasterize —— YES表明圖層及其子圖層會被整合成一個總體的圖片

  • 使用了shouldRasterize ,就要同步設置rasterizationScale來匹配屏幕

    layer.rasterizationScale = [UIScreen mainScreen].scale;

5. 變換

→ 仿射變換affineTransform

是`CGAffineTransform`類型。`Core Graphics`框架對象。提供以下函數建立:
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)

使用以下函數,初始化生成一個什麼都不作的變換,也就是建立一個CGAffineTransform類型的空值,矩陣論中稱做單位矩陣

CGAffineTransformIdentity

混合兩個已經存在的變換矩陣,使用以下方法,在兩個變換的基礎上建立一個新的變換:

CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
  • UIView能夠經過transform屬性作變換,對應CALayeraffineTransform屬性

    tip:旋轉常量M_PI是一個弧度單位。弧度用數學常量pi的倍數表示。能夠用如下公式進行弧度角度換算

    #define DEGREES_TO_RADIANS(x) ((x)/180.0 *M_PI)

    這裏要注意的是:旋轉的時候會尋找最短路徑進行旋轉。好比弧度大於pi,就會逆時針旋轉

  • 混合變換 —— 使用如下函數能夠在一個變換的基礎上作更深層次的變換

    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;
    };
  • 提供的建立函數

    看起來和affineTransform相似,可是平移和縮放多了一個 z 參數,旋轉除了弧度參數,還多了x、y、z 三個參數,分別表明每一個方向軸的旋轉

    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中的參數若是爲負數先按軸翻轉再進行縮放
    接下來就說說怎麼在應用顯示擬真的3D效果

  • 透視投影

    爲了修正視圖的遠近不一樣的縮放比例,咱們引入投影變換。經過修改矩陣中的m34元素控制

    m34的默認值是0,咱們能夠經過設置m34爲-1.0 / d來應用透視效果,d表明了想象中視角相機和屏幕之間的距離,以像素爲單位。不須要計算,只須要估算一個就行了。一般500-1000就很好了。

    減小距離的值會加強透視效果,而一個很是大的值會讓它基本失去透視效果繞y軸旋轉45度並添加透視投影效果

    當視圖遠離觀察者的時候物體會變小變遠,當遠離到必定距離的時候,就縮成了一個點,因而視角內的全部物體都匯聚消失在了同一個點。

    接下來就說說關於這個點的事

  • 滅點

    在現實中,這個點一般是物體的中點,爲了在應用中建立擬真效果 ,這個點應該是屏幕中點,或者至少是全部3D對象的中心點

    CAAnimation定義了這個點在變換圖層的anchorPoint(一般位於圖層中心,但也有例外),當圖層發生變換的時候,這個點永遠是變換以前的anchorPoint位置

    改變position就改變了圖層的anchorPoint,因此爲了讓全部3D視圖共用一個滅點,能夠先把視圖放在屏幕中央,而後經過變換移動到指定位置

    幸運的是,蘋果已經幫助咱們把上面這個比較繁瑣的事情封裝了

  • sublayerTransform屬性

    是一個CATransform3D類型。它影響到所有子圖層。如此咱們能夠統一設置子圖層的透視變換和共享滅點。

  • 其餘關於3D的屬性

    當把視圖繞着Y軸旋轉180度,咱們就能夠看到視圖的背面。繪製的就是視圖的鏡像。能夠經過doubleSided設置是否繪製視圖背面。

    扁平化圖層:
    • [ ] 1.繞Z軸旋轉的兩個圖層作相反的旋轉操做,第二個圖層作的旋轉會被第一個圖層旋轉抵消。

    • [ ] 2.而繞X軸和Y軸旋轉的不一樣圖層作相反的旋轉操做並不會相互抵消。

    緣由是儘管Core Animation圖層存在於3D空間以內,但它們並不都存在同一個3D空間。每一個圖層的3D場景實際上是扁平化的,當你從正面觀察一個圖層,看到的實際上由子圖層建立的想象出來的3D場景

    至少當你用正常的CALayer的時候是這樣,CALayer有一個叫作CATransformLayer的子類能夠解決這個問題

→ 固體對象

圖書地址

相關文章
相關標籤/搜索