一、前沿
1、三維坐標(biāo)系:視角垂直與屏幕而言,x軸向右,y軸向下,z軸垂直屏幕向外,二維坐標(biāo)系只有x軸和y軸
2、坐標(biāo)系原點(diǎn):ios默認(rèn)以圖層的左上角點(diǎn)為坐標(biāo)原點(diǎn)
3、圖層的錨點(diǎn)anchorPoint:是一個(gè)CGPoint值,x,y取值范圍(0~1),默認(rèn)情況都是圖層的中心位置為(0.5,0.5) 對于圖層本身而言,顧名思義,錨點(diǎn)就用來定位圖層的點(diǎn),保持不動(dòng)的點(diǎn)。錨點(diǎn)有兩個(gè)職能:(1)與position一同確定圖層相對于父圖層的位置;(2)作為圖層旋轉(zhuǎn)、平移、縮放的中心。
4、決定圖層位置的position:圖層的錨點(diǎn)相對于父圖層坐標(biāo)系原點(diǎn)的偏移。
二、概述
CGAffineTransform
CGAffineTransform是一個(gè)用于處理形變的類,其可以改變控件的平移、縮放、旋轉(zhuǎn)等,其坐標(biāo)系統(tǒng)采用的是二維坐標(biāo)系,即向右為x軸正方向,向下為y軸正方向
在UIView中有一個(gè)transform屬性便是專門用來控制形變的
CATransform3D
CATransform3D是一個(gè)用于處理3D形變的類,其可以改變控件的平移、縮放、旋轉(zhuǎn)、斜交等,其坐標(biāo)系統(tǒng)采用的是三維坐標(biāo)系,即向右為x軸正方向,向下為y軸正方向,垂直屏幕向外為z軸正方向,其中旋轉(zhuǎn)的時(shí)候遵守右手原則,大拇指指向其正負(fù)對應(yīng)的方向,拇指握拳旋轉(zhuǎn)的方向?yàn)槠滢D(zhuǎn)動(dòng)方向
在CALayer中有一個(gè)transform屬性便是專門用來控制3D形變的
CGAffineTransform是可以在UIView的視圖上進(jìn)行處理的,并且只是二階矩陣,只有tx和ty兩個(gè)方向,CATransform3D只能在layer層進(jìn)行操作處理,是三階矩陣,多了一個(gè)ty方向
三、仿射變化

剛體變化就是每個(gè)方向上都是保持單位的標(biāo)準(zhǔn),不會(huì)發(fā)生形變,而放大縮小,旋轉(zhuǎn)之類的都是仿射變換,圖形的每個(gè)位置都是一個(gè)有向的 向量 ,仿射變化就是 乘以一個(gè)矩陣。




那么縮放的本質(zhì)意義就是在x,y,z軸上面乘以正方向上的有向向量進(jìn)行縮放
CGAffineTransform類型屬于Core Graphics框架,Core Graphics是一個(gè)2D繪圖API,并且CGAffineTransform僅僅對2D變換有效
仿射變換矩陣是一個(gè)3×3的矩陣,如下圖所示:

因?yàn)榈谌锌偸?0,0,1),所以CGAffineTransform數(shù)據(jù)結(jié)構(gòu)只包含前兩列的值。
如果一個(gè)仿射變換矩陣乘以一個(gè)代表圖形上一點(diǎn)(x, y)的行向量,則會(huì)生成一個(gè)新的向量表示對應(yīng)的點(diǎn)(x', y'),公式表示如下:

至于是如何計(jì)算的,看下面公式:

這里根據(jù)計(jì)算公式可以看出,要是想在x軸的方向進(jìn)行拉伸的時(shí)候,只需要讓x‘變動(dòng)即可即讓a發(fā)生對應(yīng)變化,b和d保持單位方向上的不變即可在x軸上發(fā)生形變
CATransform3D是在Core Animation框架中使用的標(biāo)準(zhǔn)變換矩陣,它能夠讓圖層在3D空間內(nèi)移動(dòng)、旋轉(zhuǎn)或者放縮。CATransform3D 是一個(gè)可以在3維空間內(nèi)做變換的4x4的矩陣。

一個(gè)三維空間上的點(diǎn)(x, y, z)乘以一個(gè)CATransform3D矩陣,則會(huì)得到一個(gè)對應(yīng)的三維空間上的點(diǎn)(x', y' z')。

四、CGAffineTransform使用和介紹
CGAffineTransform是一個(gè)結(jié)構(gòu)體,里面包含的信息如下:
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
1、a 和 d 用來表示 x 軸和 y 軸的縮放系數(shù)。
2、b 和 c 用來表示旋轉(zhuǎn)和剪切變換的元素。
3、tx 和 ty 分別代表 x 軸和 y 軸的平移距離。
方法介紹
-
平移
CGAffineTransformMakeTranslation實(shí)現(xiàn)以初始位置為基準(zhǔn),在x軸方向上平移x單位,在y軸方向上平移y單位
// 格式
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
// 樣例
self.demoImageView.transform = CGAffineTransformMakeTranslation(100, 100);
CGAffineTransformTranslate實(shí)現(xiàn)以一個(gè)已經(jīng)存在的形變?yōu)榛鶞?zhǔn),在x軸方向上平移x單位,在y軸方向上平移y單位
- 平移CGAffineTransformMakeTranslation原理
self.demoImageView.transform = CGAffineTransformMakeTranslation(100, 100);
self.demoImageView.transform = CGAffineTransformMake(1, 0, 0, 1, 100, 100);
-
縮放
CGAffineTransformMakeScale實(shí)現(xiàn)以初始位置為基準(zhǔn),在x軸方向上縮放x倍,在y軸方向上縮放y倍
// 格式
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
// 樣例
self.demoImageView.transform = CGAffineTransformMakeScale(2, 0.5);
當(dāng)sx為正值時(shí),會(huì)在x軸方向上縮放x倍,反之,則在縮放的基礎(chǔ)上沿著豎直線翻轉(zhuǎn);當(dāng)sy為正值時(shí),會(huì)在y軸方向上縮放y倍,反之,則在縮放的基礎(chǔ)上沿著水平線翻轉(zhuǎn)
CGAffineTransformScale實(shí)現(xiàn)以一個(gè)已經(jīng)存在的形變?yōu)榛鶞?zhǔn),在x軸方向上縮放x倍,在y軸方向上縮放y倍
- 縮放CGAffineTransformMakeScale原理
self.demoImageView.transform = CGAffineTransformMakeScale(2, 0.5);
self.demoImageView.transform = CGAffineTransformMake(2, 0, 0, 0.5, 0, 0);
-
旋轉(zhuǎn)
CGAffineTransformMakeRotation實(shí)現(xiàn)以初始位置為基準(zhǔn),將坐標(biāo)系統(tǒng)逆時(shí)針旋轉(zhuǎn)angle弧度(弧度=π/180×角度,M_PI弧度代表180角度)
// 格式
CGAffineTransformMakeRotation(CGFloat angle)
// 樣例
self.demoImageView.transform = CGAffineTransformMakeRotation(M_PI*0.5);
當(dāng)angle為正值時(shí),表示逆時(shí)針旋轉(zhuǎn)坐標(biāo)系統(tǒng),反之順時(shí)針旋轉(zhuǎn)坐標(biāo)系統(tǒng)(因?yàn)樾D(zhuǎn)的本質(zhì)實(shí)際上是控件坐標(biāo)系的旋轉(zhuǎn)),但是可以簡單的記成正值時(shí)控件順時(shí)針,負(fù)值時(shí)為逆時(shí)針旋轉(zhuǎn)
CGAffineTransformRotate實(shí)現(xiàn)以一個(gè)已經(jīng)存在的形變?yōu)榛鶞?zhǔn),將坐標(biāo)系統(tǒng)逆時(shí)針旋轉(zhuǎn)angle弧度(弧度=π/180×角度,M_PI弧度代表180角度)
- 旋轉(zhuǎn)CGAffineTransformMakeRotation原理
self.demoImageView.transform = CGAffineTransformMakeRotation(M_PI*0.5);
self.demoImageView.transform = CGAffineTransformMake(cos(M_PI * 0.5), sin(M_PI * 0.5), -sin(M_PI * 0.5), cos(M_PI * 0.5), 0, 0);
默認(rèn)屬性
特殊地,transform屬性默認(rèn)值為CGAffineTransformIdentity,可以在形變之后設(shè)置該值以還原到最初狀態(tài)初始狀態(tài)CGAffineTransformIdentity原理
self.demoImageView.transform = CGAffineTransformIdentity;
self.demoImageView.transform = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
tx用來控制在x軸方向上的平移,ty用來控制在y軸方向上的平移;a用來控制在x軸方向上的縮放,d用來控制在y軸方向上的縮放;abcd共同控制旋轉(zhuǎn)
五、CATransform3D使用和介紹
CATransform3D的結(jié)構(gòu)體定義及各成員變量的職能如下:
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
平移因子: m41(x位置->tx) m42(y位置->ty) m43(z位置->tz)
縮放因子: m11(x位置->sx) m22(y位置->sy)m33(z位置->sz)
切變因子: m21(x位置) m12(y位置)
旋轉(zhuǎn)因子: m13(x位置) m31(y位置)
透視因子: m34(透明度,必須有旋轉(zhuǎn)角度時(shí)才能看出效果,正直/負(fù)值都有意義),m34 的默認(rèn)值是0,可以通過設(shè)置 m34 為-1.0 / d 來應(yīng)用透視效果, d 代表了想象中視角相機(jī)和屏幕之間的距離,以像素為單位,實(shí)際使用中大概估算一個(gè)就好,一般在500~1000的范圍內(nèi),一個(gè)非常微小的值會(huì)讓它看起來更加失真,而一個(gè)非常大的值會(huì)讓它基本失去透視效果。
- 平移
/* Returns a transform that translates by '(tx, ty, tz)': * t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]. */
//返回一個(gè)平移變換的transform3D對象 tx,ty,tz 對應(yīng)x,y,z軸的平移
CATransform3D CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz);
/* Translate 't' by '(tx, ty, tz)' and return the result: * t' = translate(tx, ty, tz) * t. */
//在某個(gè)transform3D變換的基礎(chǔ)上進(jìn)行平移變換,t是上一個(gè)transform3D,其他參數(shù)同上
CATransform3D CATransform3DTranslate (CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz);
返回的是一個(gè)t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]矩陣,x,y,z都是正方向上的單位向量,tx ty tz分別代表沿著xyz移動(dòng)的距離
- 縮放
/* Returns a transform that scales by `(sx, sy, sz)':* t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1]. */
//x,y,z分別對應(yīng)x軸,y軸,z軸的縮放比例
CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
//在一個(gè)transform3D變換的基礎(chǔ)上進(jìn)行縮放變換,其他參數(shù)同上
CATransform3D CATransform3DScale (CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz);
縮放的方式處理的是返回 t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1].該矩陣,sx,sy,sz的值分別對應(yīng)著在xyz軸的方向上分別進(jìn)行縮放的比例
-
旋轉(zhuǎn)
旋轉(zhuǎn)方向.png
/* Returns a transform that rotates by 'angle' radians about the vector* '(x, y, z)'. If the vector has length zero the identity transform is * returned. */
//angle參數(shù)是旋轉(zhuǎn)的角度,為弧度制 0-2π
//x,y,z決定了旋轉(zhuǎn)圍繞的中軸,取值為-1——1之間,例如(1,0,0),則是繞x軸旋轉(zhuǎn)(0.5,0.5,0),則是繞x軸與y軸中
//間45度為軸旋轉(zhuǎn),依次進(jìn)行計(jì)算
CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
//在一個(gè)transform3D的基礎(chǔ)上進(jìn)行旋轉(zhuǎn)變換,其他參數(shù)如上
CATransform3D CATransform3DRotate (CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
在旋轉(zhuǎn)過程中,可以設(shè)置m34來控制想象中視角相機(jī)和屏幕之間的距離,來實(shí)現(xiàn)遠(yuǎn)小近大的一個(gè)視覺效果,同時(shí)必須在賦值transform之前設(shè)置才會(huì)生效
其中在旋轉(zhuǎn)過程中的還有一個(gè)就是滅點(diǎn):當(dāng)在透視角度繪圖的時(shí)候,遠(yuǎn)離相機(jī)視角的物體將會(huì)變小變遠(yuǎn),當(dāng)遠(yuǎn)離到一個(gè)極限距離,它們可能就縮成了一個(gè)點(diǎn),于是所有的物體最后都匯聚消失在同一個(gè)點(diǎn),該點(diǎn)就叫 滅點(diǎn)。 通常位于圖層中心,但也有例外,這就是說,當(dāng)圖層發(fā)生變換時(shí),這個(gè)點(diǎn)永遠(yuǎn)位于圖層變換之前 anchorPoint(矛點(diǎn)) 的位置。 當(dāng)改變一個(gè)圖層的 position ,同時(shí)改變了它的滅點(diǎn),做 3D 變換的時(shí)候,如果想把視圖通過調(diào)整 m34 來讓它更加有 3D 效果,應(yīng)該首先把它放置于屏幕中央,然后通過平移來把它移動(dòng)到指定位置(而不是直接改變它的position ),這樣所有的 3D 圖層都共享一個(gè)滅點(diǎn)。也就是說想通過m34設(shè)置透明度的時(shí)候,必須保證不改變它的position(之前動(dòng)畫的時(shí)候,改變過position位置之后,位置跟透明度永遠(yuǎn)對不上),如果想位置發(fā)生變動(dòng),就使用平移來操作。
- 組合變化
/* Concatenate 'b' to 'a' and return the result: t' = a * b. CATransform3DConcat */
// 將視圖的anchorPoint設(shè)置為(0.5, 1.0),即視圖的底邊中心點(diǎn)
view.layer.anchorPoint = CGPointMake(0.5, 1.0);
// 創(chuàng)建一個(gè)繞x軸旋轉(zhuǎn)45度和縮放變換的組合變換矩陣
CGFloat angle = M_PI_2;
CATransform3D rotationTransform = CATransform3DMakeRotation(angle, 1.0, 0.0, 0.0);
CATransform3D scaleTransform = CATransform3DMakeScale(0.8, 1.2, 1.0);
CATransform3D transform = CATransform3DConcat(rotationTransform, scaleTransform);
示列:先將視圖的anchorPoint屬性設(shè)置為(0.5, 1.0),以保持視圖的底邊中心點(diǎn)不變。然后使用CATransform3DMakeRotation方法創(chuàng)建了一個(gè)繞x軸旋轉(zhuǎn)角度為90度的旋轉(zhuǎn)變換矩陣,并使用CATransform3DMakeScale方法創(chuàng)建了一個(gè)縮放變換矩陣,其中x軸方向上的縮放因子設(shè)為0.8,y軸方向上的縮放因子設(shè)為1.2。接著使用CATransform3DConcat方法將兩個(gè)變換矩陣組合成一個(gè)變換矩陣,并將該矩陣應(yīng)用到視圖的transform屬性上,實(shí)現(xiàn)了視圖在旋轉(zhuǎn)過程中上半部分縮小一點(diǎn),下半部分放大一點(diǎn)的效果。
CATransform3DConcat是將其兩個(gè)CATransform3D類型的矩陣進(jìn)行重新組合后生成一個(gè)新的矩陣來處理
- 默認(rèn)屬性
/* The identity transform: [1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]. */
CA_EXTERN const CATransform3D CATransform3DIdentity
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
返回的矩陣是[1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1].
- 判斷值
判斷t是否是最初的對象*/
CA_EXTERN bool CATransform3DIsIdentity (CATransform3D t)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
/* Returns true if 'a' is exactly equal to 'b'. 判斷a和b是否相同*/
CA_EXTERN bool CATransform3DEqualToTransform (CATransform3D a,
CATransform3D b)
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- 反轉(zhuǎn)
/* Invert 't' and return the result. Returns the original matrix if 't' * has no inverse. */
//將一個(gè)旋轉(zhuǎn)的效果進(jìn)行翻轉(zhuǎn)
CATransform3D CATransform3DInvert (CATransform3D t);
-
CATransform3D與CGAffineTransform的轉(zhuǎn)換
CGAffineTransform是UIKit框架中一個(gè)用于變換的矩陣,其作用與CATransform類似,只是其可以直接作用于View,而不用作用于layer,這兩個(gè)矩陣也可以進(jìn)行轉(zhuǎn)換,方法如下:
//將一個(gè)CGAffinrTransform轉(zhuǎn)化為CATransform3D
CATransform3D CATransform3DMakeAffineTransform (CGAffineTransform m);
//判斷一個(gè)CATransform3D是否可以轉(zhuǎn)換為CAAffineTransform
bool CATransform3DIsAffine (CATransform3D t);
//將CATransform3D轉(zhuǎn)換為CGAffineTransform
CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);
-
獲取結(jié)構(gòu)體
+(NSValue *)valueWithCATransform3D:(CATransform3D)t,是 NSValue 類的一個(gè)類方法,用于將 CATransform3D 結(jié)構(gòu)體 t 包裝成 NSValue 對象。這樣做的目的是將 CATransform3D 這種 C 語言結(jié)構(gòu)體轉(zhuǎn)換為 Objective-C 對象,以便能夠方便地在 Objective-C 的集合類中存儲(chǔ)和傳遞。通過調(diào)用 valueWithCATransform3D: 方法,可以創(chuàng)建一個(gè) NSValue 對象,其中包含了傳入的 CATransform3D 結(jié)構(gòu)體。這樣就可以將 CATransform3D 結(jié)構(gòu)體放入 NSArray、NSDictionary 等 Objective-C 集合類中,方便進(jìn)行處理和傳遞。
參考文章
1.CATransform3D基本動(dòng)畫
2.了解CATransform3D,請看這里
3.核心動(dòng)畫-仿射變化
