iOS動畫:帶時分秒指標的時鐘動畫(上)

非典型技術宅發表於2017-07-27

經過幾次實驗,發現如果分享的文章能構成系列,效果會非常好。同時自己也能收穫很大,能夠整塊整塊的複習,也能夠幫助自己更深入的塊狀學習知識。對自己梳理線條,整理知識體系作用非常大。

所以這次還是打算用這種方式,一起來分享一下iOS中關於動畫的部分。iOS 的動畫渲染簡直是帥的不要不要的,哈哈。其實當初就是因為iOS的動畫,還有iOS的對手勢的處理深深的打動了我,才讓我這樣一個高齡中年老男人開始了iOS這條路。啦啦啦啦~

開始我們們的第一篇內容。

1. 最終實現的效果以及思維導圖

實現的效果。不小心暴露了寫文章的時間。-_-+++

實現效果
實現效果

實現的步驟思維導圖:

思維導圖.png
思維導圖.png

2. CALayer

其實今天分享的主角是CALayer。因為所有的動畫都是在CALayer上完成的。

  • 在iOS中,看得見摸得著的東西基本上都是UIView,比如一個按鈕、一個文字標籤、一個文字輸入框、一個圖示等等,這些都是UIView
  • 其實UIView之所以能顯示在螢幕上,完全是因為它內部的一個圖層
  • 在建立UIView物件時,UIView內部會自動建立一個圖層(即CALayer物件),通過UIView的layer屬性可以訪問這個層
    @property(nonatomic,readonly,retain) CALayer *layer;
  • 當UIView需要顯示到螢幕上時,會呼叫drawRect:方法進行繪圖,並且會將所有內容繪製在自己的圖層上,繪圖完畢後,系統會將圖層拷貝到螢幕上,於是就完成了UIView的顯示
  • 換句話說,UIView本身不具備顯示的功能,是它內部的層才有顯示功能

2.1 CALayer的基本屬性

屬性型別 屬性名稱 用途
@property CGFloat borderWidth; 邊寬
@property CGColorRef borderColor; 邊的顏色
@property CGColorRef backgroundColor; 背景顏色
@property float opacity; 透明度
@property CGColorRef shadowColor; 陰影顏色
@property float shadowOpacity; 陰影透明度,設定範圍0~1。
@property CGSize shadowOffset; 陰影的偏移
@property CGFloat shadowRadius; 陰影的模糊度
@property(strong) id contents; 內容。可以設定為圖片,但是需要橋接。
@property CGFloat cornerRadius; 圓角
@property CGRect bounds; Layer的大小
@property CGPoint position; 預設情況下相當於UIView的center
@property CGPoint anchorPoint; position的錨點
@property CATransform3D transform; 用來做形變的,是一個矩陣。可以理解為結構體。
@property BOOL masksToBounds; 超過部分進行裁剪
  • 設定陰影的時候,陰影顏色+陰影偏移(或者陰影路徑)+陰影透明度缺一不可。
  • 陰影模糊度如果不設定,預設值就是3.0000。
  • 陰影的路徑:
    • 設定了陰影的路徑,就不再需要設定陰影的偏移量了。
    • 設定了陰影的路徑之後,也不能再設定masksToBounds。因為超過部分會被裁減。
      以實現下圖為例:

Paste_Image.png
Paste_Image.png

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];

    [self.view addSubview:imageView];

//    設定背景顏色。注意UIColor 和 CGColor之間的互換
    imageView.layer.backgroundColor = [UIColor grayColor].CGColor;

//    生成一個path
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(-10, -10, imageView.bounds.size.width + 20, imageView.bounds.size.height + 20)];
//    設定陰影path
    imageView.layer.shadowPath = path.CGPath;

//    設定陰影顏色
    imageView.layer.shadowColor = [UIColor lightGrayColor].CGColor;

//    設定陰影透明度
    imageView.layer.shadowOpacity = 0.5;複製程式碼

2.2 手動建立一個CALayer

  • 建立CALayer
  • 在設定frame的時候,內部同時設定了position,bounds.size 都會發生改變。
  • 設定position,就和設定UIView的center一樣的。
  • 記得要新增到父CALayer上。
 CALayer *layer = [[CALayer alloc] init];

 // ------------------- 設定位置大小 ---------------------
 // 方式一: 直接設定 frame
 // layer.frame = CGRectMake(50, 50, 200, 200);


 // 方式二:
 // 先設定大小
 layer.bounds = CGRectMake(0, 0, 100, 100);
 // 再設定位置(預設情況下 position 指的是 center。)
 layer.position = CGPointMake(150, 150);
 // ------------------- 設定位置大小 ---------------------

 layer.backgroundColor = [UIColor redColor].CGColor;
 layer.opacity = 0.7;
 [self.view.layer addSublayer:layer];
 }複製程式碼

2.3 transform

從這裡開始,我們們的座標軸就變成了xyz三個軸向了,因為圖案也會變成立體的了。

  • 從 layer 的中心點到 給定的座標點之間連一條線, 然後以這個線為中心軸, 開始旋轉
    self.myLayer.transform = CATransform3DMakeRotation(M_PI_4, 10, 20, 30);複製程式碼

    這段程式碼的意思就是說從{0,0,0}這個點,到{10,20,30}這個點,劃一根線。圖形繞著這根線,旋轉M_PI_4度數。

2.3.1 修改透視

在真實世界中,當物體遠離我們的時候,由於視角的原因看起來會變小,理論上說遠離我們的檢視的邊要比靠近視角的邊跟短,但實際上並沒有發生,而我們當前的視角是等距離的,也就是在3D變換中任然保持平行,和之前提到的仿射變換類似。

“為了做一些修正,我們需要引入投影變換(又稱作z變換)來對除了旋轉之外的變換矩陣做一些修改,Core Animation並沒有給我們提供設定透視變換的函式,因此我們需要手動修改矩陣值,幸運的是,很簡單:CATransform3D的透視效果通過一個矩陣中一個很簡單的元素來控制:m34。m34用於按比例縮放X和Y的值來計算到底要離視角多遠。”

Excerpt From: 鐘聲. “ios核心動畫高階技巧.” iBooks.

Paste_Image.png
Paste_Image.png

  • 通過修改transform的m34來達到效果
  • transform可以看成是一個結構體,所以修改的時候需要通過一箇中間量才能修改。
  • m34的預設值是0,可以通過設定m34為-1.0 / d來應用透視效果
  • d代表了想象中視角相機和螢幕之間的距離,以畫素為單位,那應該如何計算這個距離呢?實際上並不需要,大概估算一個就好了。”
  • “因為視角相機實際上並不存在,所以可以根據螢幕上的顯示效果自由決定它的防止的位置。通常500-1000就已經很好了”

Excerpt From: 鐘聲. “ios核心動畫高階技巧.” iBooks.

struct CATransform3D{  
  CGFloat     m11(x縮放),   m12(y切變),   m13(旋轉),   m14();
  CGFloat     m21(x切變),   m22(y縮放),   m23,        m24;
  CGFloat     m31(旋轉),    m32,         m33,         m34(透視效果,要有旋轉角度才能看出效果);
  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;

//    旋轉加透視
    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

  • 預設情況下position相當於UIView 的center
  • position決定了layer在父上的位置。
  • 但是anchorPoint決定了position在自身的位置。
  • anchorPoint的數值只能是0~1。所以是按照百分比計算的。

3. 隱式動畫

  • 當對非Root Layer的部分屬性進行修改時,預設會自動產生一些動畫效果
  • 所有的非Root Layer,也就是手動建立的CALayer物件,都存在著隱式動畫
  • 所有註釋裡面寫著有Animatable,這個屬性就有隱式動畫效果。

Paste_Image.png
Paste_Image.png

3.1 幾個常見的Animatable Properties:

  • bounds:用於設定CALayer的寬度和高度。修改這個屬性會產生縮放動畫
  • backgroundColor:用於設定CALayer的背景色。修改這個屬性會產生背景色的漸變動畫
  • position:用於設定CALayer的位置。修改這個屬性會產生平移動畫

3.2 關閉隱式動畫

  • 可以通過動畫事務(CATransaction)關閉預設的隱式動畫效果
  • 關閉或者修改隱式動畫的步驟:
    • 開啟動畫事物
    • 關閉動畫效果或者修改動畫事件
    • 設定動畫完成後的動作(可以不設定)
    • 修改屬性
      • 提交
        //開啟
        [CATransaction begin];
        //關閉動畫
        [CATransaction setDisableActions:YES];
        //修改屬性
        self.myview.layer.position = CGPointMake(10, 10);
        //提交
        [CATransaction commit];複製程式碼

寶貝兒們,我錯了。寫到這裡發現已經辣麼長辣麼長了,再寫下去這篇該沒有人看了。

那麼,那麼。。。。就臨時變卦吧,把這篇文章變成上下集吧。哈哈~就這麼愉快的自己打自己的臉了~

所以,證明一個道理。計劃都只是用來計劃的,樹立一個目標,能不能實現再說。哈哈~

相關文章