經過幾次實驗,發現如果分享的文章能構成系列,效果會非常好。同時自己也能收穫很大,能夠整塊整塊的複習,也能夠幫助自己更深入的塊狀學習知識。對自己梳理線條,整理知識體系作用非常大。
所以這次還是打算用這種方式,一起來分享一下iOS中關於動畫的部分。iOS 的動畫渲染簡直是帥的不要不要的,哈哈。其實當初就是因為iOS的動畫,還有iOS的對手勢的處理深深的打動了我,才讓我這樣一個高齡中年老男人開始了iOS這條路。啦啦啦啦~
開始我們們的第一篇內容。
1. 最終實現的效果以及思維導圖
實現的效果。不小心暴露了寫文章的時間。-_-+++
實現的步驟思維導圖:
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
。因為超過部分會被裁減。
以實現下圖為例:
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.
- 通過修改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,這個屬性就有隱式動畫效果。
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];複製程式碼
- 提交
寶貝兒們,我錯了。寫到這裡發現已經辣麼長辣麼長了,再寫下去這篇該沒有人看了。
那麼,那麼。。。。就臨時變卦吧,把這篇文章變成上下集吧。哈哈~就這麼愉快的自己打自己的臉了~
所以,證明一個道理。計劃都只是用來計劃的,樹立一個目標,能不能實現再說。哈哈~