UIView的transform
屬性是CGAffineTransform類型函似,用于在二維空間做旋轉(zhuǎn)槐脏,縮放和平移。
CGAffineTransform是一個可以和二維空間向量做乘法的3 * 2矩陣撇寞。如下圖:
仿射變換
當(dāng)對圖層應(yīng)用變換矩陣顿天,圖層矩形內(nèi)的每一個點都被相應(yīng)的做變換堂氯,從而形成一個新的形狀。CGAffineTransform
仿射變換的仿射
意思是無論變換矩陣用什么值牌废,圖層中平行的兩條線在變換之后仍然保持平行咽白。
看了上邊的一些概念,可能覺得霧里云里鸟缕,不如我們直接上代碼和效果晶框。
CGAffineTransform是CG開頭的,也就是說是在Core Graphics框架里的懂从,這個框架為我們提供了好用的函數(shù)可以讓我們不必自己去親自計算矩陣的相乘授段。
//常用的三個函數(shù):
CGAffineTransformMakeRotation(CGFloat angle)
// 旋轉(zhuǎn) 表示旋轉(zhuǎn)多少角度,如果是正數(shù)的番甩,會按照順時針旋轉(zhuǎn)侵贵,如果負(fù)數(shù),則逆時針旋轉(zhuǎn)缘薛。
//注意窍育,這個函數(shù)傳入的參數(shù)不是我們平常說的角度而是弧度。如果覺得分不清楚宴胧,或總是混淆的話漱抓,可以用下邊給出的兩個宏做計算。
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
// 縮放 兩個參數(shù)分別表示水平方向(x軸)和豎直方向(y軸)的縮放比例恕齐。
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
// 平移 兩個參數(shù)分別表示水平方向(x軸)和豎直方向(y軸)上平移的位移(以點`point`計)
//弧度轉(zhuǎn)角度
#define RADIANS_TO_DEGREES(x) ((x)/M_PI*180.0)//傳入弧度 eg: M_PI_4
//角度轉(zhuǎn)弧度
#define DEGREES_TO_RADIANS(x) ((x)/180.0*M_PI)//傳入度數(shù)eg:45度
- (void)test0
{
///右轉(zhuǎn)90度
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2);
//以下兩個賦值效果一樣乞娄。最終都是作用于layer上。
self.label.transform = transform;
// self.label.layer.affineTransform = transform;
}
- (void)test1
{
//水平方向縮小0.5倍显歧,豎直方向縮小0.8倍
CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.8);
self.label.layer.affineTransform = transform;
}
- (void)test2
{
//水平方向上平移20补胚;豎直方向平移10
CGAffineTransform transform = CGAffineTransformMakeTranslation(20, 10);
self.label.layer.affineTransform = transform;
}
圖中藍(lán)色視圖是紅色視圖的父視圖,作為初始狀態(tài)和形變后的樣子做對比追迟。第一張是選擇溶其,第二種是縮放,第三張是平移敦间。
混合變換
如果想讓一個view既縮放又旋轉(zhuǎn)瓶逃,就用到混合變換了。Core Graphics也給我們提供了方便好用的接口廓块。
/*
CGAffineTransformIdentity: //單位矩陣
“CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)”
//兩個變換的基礎(chǔ)上生成另一個變換
“CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);”
*/
@property(nonatomic) CGAffineTransform transform; // default is CGAffineTransformIdentity. animatable
//UIView的transform的屬性的默認(rèn)值就是CGAffineTransformIdentity厢绝。
調(diào)用這些函數(shù)要傳入一個初始值,即CGAffineTransformIdentity
带猴,這個是CGAffineTransform類型的空值昔汉。也是UIView的transform屬性的默認(rèn)值。以上幾個函數(shù)拴清,可以將不同的效果疊加靶病。
- (void)mixTest0
{
CGAffineTransform transfrom = CGAffineTransformIdentity;
transfrom = CGAffineTransformRotate(transfrom,DEGREES_TO_RADIANS(60));//旋轉(zhuǎn)60度
transfrom = CGAffineTransformScale(transfrom, 0.5, 0.6);
transfrom = CGAffineTransformTranslate(transfrom, 0, 50);
//沒有垂直向下移動50会通,因為會疊加上兩個形變的結(jié)果,相當(dāng)于向斜下方移動了50 * 0.6
self.label.layer.affineTransform = transfrom;
//“后邊的形變會作用在之前形變的結(jié)果之上,也就是說旋轉(zhuǎn)之后的平移和平移之后的旋轉(zhuǎn)結(jié)果可能不同娄周。
}
-
3D變換
上邊說的仿射變換和混合變換都是在平面上的效果承二,圖層layer的transform
屬性(CATransform3D類型 )可以讓圖層在3D空間內(nèi)移動或者旋轉(zhuǎn)笛臣。CATransform3D
是在3維空間內(nèi)做變換的4 * 4的矩陣。
//3D的變換比仿射變換多了一個角度和一個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)”
下圖是3D空間內(nèi)鸵荠,針對x,y,z軸以及其旋轉(zhuǎn)方向稠鼻。
- (void)test3D_x
{
//在豎直方向壓縮了 實際是沿著豎直方向傾斜了45度去看 如果是90度則完全看不到
CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 1, 0, 0);
self.label.layer.transform = transform;
}
- (void)test3D_y
{
//效果是在水平方向壓縮了 實際是沿著水平方向傾斜了45度去看 如果是90度則完全看不到
CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
self.label.layer.transform = transform;
}
- (void)test3D_z//效果是在正對著用戶的方向上旋轉(zhuǎn)了45度
{
CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
self.label.layer.transform = transform;
}
其實單直接對以上函數(shù)的參數(shù)做變動商佑,看不出太多效果耕挨,和自己想象中的3D效果不一樣【槌梗看著好像是圖層進(jìn)行了壓縮技肩,其實是因為相當(dāng)于我們換個角度去看圖層導(dǎo)致。
要想達(dá)到透視效果浮声,我們需要對
CATransform3D
這個矩陣做操作。
-
透視
我們不需要去管矩陣計算怎么復(fù)雜旋奢,我們只要控制一個矩陣中m34
的值就可以泳挥。m34
用于按比例縮放X和Y的值來計算到底要離視角有多遠(yuǎn)。所以我們可以用CATransform3D
中m34
的值用來做透視至朗。
m34
的值默認(rèn)是0屉符,可以通過設(shè)置m34
為-1.0 / d
來實現(xiàn)透視效果,d的取值范圍500~1000
锹引。
- (void)testPerspective_x
{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = - 1.0 / 500;
transform = CATransform3DRotate(transform, M_PI_4, 1, 0, 0);
self.label.layer.transform = transform;
}
- (void)testPerspective_y
{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = - 1.0 / 500;
transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
self.label.layer.transform = transform;
}
- (void)testPerspective_z
{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = - 1.0 / 500;
transform = CATransform3DRotate(transform, M_PI_4, 0, 0, 1);
self.label.layer.transform = transform;
}
結(jié)果如上圖矗钟,我們設(shè)置了
m34
的值后,看著才有了3D的效果嫌变。具體你效果需要什么樣吨艇,可以根據(jù)自己的需要進(jìn)行設(shè)置。總結(jié):
變換這塊自己平常不怎么用到腾啥,偶爾需要用到的時候也總想不起來东涡,在這里總結(jié)一下,以后便于查找學(xué)習(xí)倘待。希望對看到的讀者也有所幫助疮跑。感謝下邊書籍的翻譯者,感謝凸舵。配套Demo可供參考祖娘。
參考書籍:ios核心動畫高級技巧