5奴潘、變換

片頭曲 曲曲曲曲曲曲曲曲曲曲曲曲曲

5變換

5.1 仿射變換

實(shí)際上UIView的transform屬性是一個(gè)CGAffineTransform類型,用于在二維空間做旋轉(zhuǎn)影钉,縮放和平移画髓。CGAffineTransform是一個(gè)可以和二維空間向量(例如CGPoint)做乘法的3X2的矩陣

當(dāng)對(duì)圖層應(yīng)用變換矩陣,圖層矩形內(nèi)的每一個(gè)點(diǎn)都被相應(yīng)地做變換平委,從而形成一個(gè)新的四邊形的形狀雀扶。CGAffineTransform中的“仿射”的意思是無(wú)論變換矩陣用什么值,圖層中平行的兩條線在變換之后任然保持平行肆汹,CGAffineTransform可以做出任意符合上述標(biāo)注的變換愚墓,

創(chuàng)建一個(gè)CGAffineTransform

Core Graphics提供了一系列函數(shù),對(duì)完全沒(méi)有數(shù)學(xué)基礎(chǔ)的開(kāi)發(fā)者也能夠簡(jiǎn)單地做一些變換昂勉。如下幾個(gè)函數(shù)都創(chuàng)建了一個(gè)CGAffineTransform實(shí)例:

CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)

旋轉(zhuǎn)和縮放變換都可以很好解釋--分別旋轉(zhuǎn)或者縮放一個(gè)向量的值浪册。平移變換是指每個(gè)點(diǎn)都移動(dòng)了向量指定的x或者y值--所以如果向量代表了一個(gè)點(diǎn),那它就平移了這個(gè)點(diǎn)的距離岗照。

demo如下:

@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *layerView;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //rotate the layer 45 degrees
    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
    self.layerView.layer.affineTransform = transform;
}

@end

注意我們使用的旋轉(zhuǎn)常量是M_PI_4村象,而不是你想象的45,因?yàn)閕OS的變換函數(shù)使用弧度而不是角度作為單位攒至『裾撸弧度用數(shù)學(xué)常量pi的倍數(shù)表示,一個(gè)pi代表180度迫吐,所以四分之一的pi就是45度库菲。

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

混合變換

Core Graphics提供了一系列的函數(shù)可以在一個(gè)變換的基礎(chǔ)上做更深層次的變換,如果做一個(gè)既要縮放又要旋轉(zhuǎn)的變換志膀,這就會(huì)非常有用了熙宇。例如下面幾個(gè)函數(shù):

CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)

當(dāng)操縱一個(gè)變換的時(shí)候,初始生成一個(gè)什么都不做的變換很重要--也就是創(chuàng)建一個(gè)CGAffineTransform類型的空值溉浙,矩陣論中稱作單位矩陣烫止,Core Graphics同樣也提供了一個(gè)方便的常量:

CGAffineTransformIdentity

最后,如果需要混合兩個(gè)已經(jīng)存在的變換矩陣戳稽,就可以使用如下方法馆蠕,在兩個(gè)變換的基礎(chǔ)上創(chuàng)建一個(gè)新的變換:

CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);

我們來(lái)用這些函數(shù)組合一個(gè)更加復(fù)雜的變換,先縮小50%惊奇,再旋轉(zhuǎn)30度互躬,最后向右移動(dòng)200個(gè)像素。

- (void)viewDidLoad
{
    [super viewDidLoad]; //create a new transform
    CGAffineTransform transform = CGAffineTransformIdentity; //scale by 50%
    transform = CGAffineTransformScale(transform, 0.5, 0.5); //rotate by 30 degrees
    transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0); //translate by 200 points
    transform = CGAffineTransformTranslate(transform, 200, 0);
    //apply transform to layer
    self.layerView.layer.affineTransform = transform;
}

運(yùn)行完之后你會(huì)發(fā)現(xiàn)

圖片向右邊發(fā)生了平移赊时,但并沒(méi)有指定距離那么遠(yuǎn)(200像素)吨铸,另外它還有點(diǎn)向下發(fā)生了平移。原因在于當(dāng)你按順序做了變換祖秒,上一個(gè)變換的結(jié)果將會(huì)影響之后的變換诞吱,所以200像素的向右平移同樣也被旋轉(zhuǎn)了30度,縮小了50%竭缝,所以它實(shí)際上是斜向移動(dòng)了100像素房维。

這意味著變換的順序會(huì)影響最終的結(jié)果,也就是說(shuō)旋轉(zhuǎn)之后的平移和平移之后的旋轉(zhuǎn)結(jié)果可能不同抬纸。

5.2 3D變換

CG的前綴告訴我們咙俩,CGAffineTransform類型屬于Core Graphics框架,Core Graphics實(shí)際上是一個(gè)嚴(yán)格意義上的2D繪圖API,并且CGAffineTransform僅僅對(duì)2D變換有效阿趁。

和CGAffineTransform矩陣類似膜蛔,Core Animation提供了一系列的方法用來(lái)創(chuàng)建和組合CATransform3D
類型的矩陣,和Core Graphics的函數(shù)類似脖阵,但是3D的平移和旋轉(zhuǎn)多處了一個(gè)z參數(shù)皂股,并且旋轉(zhuǎn)函數(shù)除了angle之外多出了x,y,z三個(gè)參數(shù),分別決定了每個(gè)坐標(biāo)軸方向上的旋轉(zhuǎn):

CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) 
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

代碼使用了CATransform3DMakeRotation對(duì)視圖內(nèi)的圖層繞Y軸做了45度角的旋轉(zhuǎn)命黔,我們可以把視圖向右傾斜呜呐,

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //rotate the layer 45 degrees along the Y axis
    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.layerView.layer.transform = transform;
}

@end

透視投影

CATransform3D的透視效果通過(guò)一個(gè)矩陣中一個(gè)很簡(jiǎn)單的元素來(lái)控制:m34。

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //create a new transform
    CATransform3D transform = CATransform3DIdentity;
    //apply perspective
    transform.m34 = - 1.0 / 500.0;
    //rotate by 45 degrees along the Y axis
    transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
    //apply to layer
    self.layerView.layer.transform = transform;
}

@end

滅點(diǎn)

Core Animation定義了這個(gè)點(diǎn)位于變換圖層的anchorPoint(通常位于圖層中心悍募,但也有例外)蘑辑。這就是說(shuō),當(dāng)圖層發(fā)生變換時(shí)坠宴,這個(gè)點(diǎn)永遠(yuǎn)位于圖層變換之前anchorPoint的位置洋魂。

當(dāng)改變一個(gè)圖層的position,你也改變了它的滅點(diǎn)啄踊,做3D變換的時(shí)候要時(shí)刻記住這一點(diǎn)忧设,當(dāng)你視圖通過(guò)調(diào)m34來(lái)讓它更加有3D效果,應(yīng)該首先把它放置于屏幕中央颠通,然后通過(guò)平移來(lái)把它移動(dòng)到指定位置(而不是直接改變它的position)址晕,這樣所有的3D圖層都共享一個(gè)滅點(diǎn)。

sublayerTransform屬性

如果有多個(gè)視圖或者圖層顿锰,每個(gè)都做3D變換谨垃,那就需要分別設(shè)置相同的m34值,并且確保在變換之前都在屏幕中央共享同一個(gè)position硼控,如果用一個(gè)函數(shù)封裝這些操作的確會(huì)更加方便刘陶,但仍然有限制(例如,你不能在Interface Builder中擺放視圖)牢撼,這里有一個(gè)更好的方法匙隔。

CALayer有一個(gè)屬性叫做sublayerTransform。它也是CATransform3D類型熏版,但和對(duì)一個(gè)圖層的變換不同纷责,它影響到所有的子圖層。這意味著你可以一次性對(duì)包含這些圖層的容器做變換撼短,于是所有的子圖層都自動(dòng)繼承了這個(gè)變換方法再膳。

相較而言,通過(guò)在一個(gè)地方設(shè)置透視變換會(huì)很方便曲横,同時(shí)它會(huì)帶來(lái)另一個(gè)顯著的優(yōu)勢(shì):滅點(diǎn)被設(shè)置在容器圖層的中點(diǎn)喂柒,從而不需要再對(duì)子圖層分別設(shè)置了。這意味著你可以隨意使用position和frame來(lái)放置子圖層,而不需要把它們放置在屏幕中點(diǎn)灾杰,然后為了保證統(tǒng)一的滅點(diǎn)用變換來(lái)做平移蚊丐。

@property (weak, nonatomic) IBOutlet UIView *contintView1;

@property (weak, nonatomic) IBOutlet UIView *subView1;
@property (weak, nonatomic) IBOutlet UIView *subView2;


- (void)viewDidLoad
{
    UIImage *img = [UIImage imageNamed:@"001"];
    
    CATransform3D transtrom = CATransform3DIdentity;
    
    transtrom.m34 = -1.0f / 500.0f;
    
    self.contintView1.layer.sublayerTransform = transtrom;
    
    self.subView1.layer.contents = (id)img.CGImage;
    self.subView1.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    
    self.subView2.layer.contents = (id)img.CGImage;
    self.subView2.layer.transform = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
}

背面

將一個(gè)圖片按照y軸旋轉(zhuǎn)180度后,就會(huì)看到他的背面吭露。
self.subView1.layer.transform = CATransform3DMakeRotation(M_PI+M_PI_4, 0, 1, 0);

CATransform3D trans3d = CATransform3DIdentity;
trans3d = CATransform3DRotate(trans3d, M_PI, 0, 1, 0);

CALayer有一個(gè)叫做doubleSided的屬性來(lái)控制圖層的背面是否要被繪制吠撮。這是一個(gè)BOOL類型,默認(rèn)為YES讲竿,如果設(shè)置為NO,那么當(dāng)圖層正面從相機(jī)視角消失的時(shí)候弄屡,它將不會(huì)被繪制题禀。

self.imgVIew2.layer.doubleSided = YES;

如果設(shè)置為no 那么圖片旋轉(zhuǎn)180,是看不見(jiàn)任何東西的膀捷。

扁平化圖層

如果對(duì)包含已經(jīng)做過(guò)變換的圖層的圖層做反方向的變換將會(huì)發(fā)什么什么呢迈嘹?是不是有點(diǎn)困惑?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末全庸,一起剝皮案震驚了整個(gè)濱河市秀仲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌壶笼,老刑警劉巖神僵,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異覆劈,居然都是意外死亡保礼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門责语,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)炮障,“玉大人,你說(shuō)我怎么就攤上這事坤候⌒灿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵白筹,是天一觀的道長(zhǎng)智末。 經(jīng)常有香客問(wèn)我,道長(zhǎng)遍蟋,這世上最難降的妖魔是什么吹害? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮虚青,結(jié)果婚禮上它呀,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好纵穿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布下隧。 她就那樣靜靜地躺著,像睡著了一般谓媒。 火紅的嫁衣襯著肌膚如雪淆院。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天句惯,我揣著相機(jī)與錄音土辩,去河邊找鬼。 笑死抢野,一個(gè)胖子當(dāng)著我的面吹牛拷淘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播指孤,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼启涯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了恃轩?” 一聲冷哼從身側(cè)響起结洼,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叉跛,沒(méi)想到半個(gè)月后松忍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昧互,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年挽铁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敞掘。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叽掘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出玖雁,到底是詐尸還是另有隱情更扁,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布赫冬,位于F島的核電站浓镜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏劲厌。R本人自食惡果不足惜膛薛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望补鼻。 院中可真熱鬧哄啄,春花似錦雅任、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至锌半,卻和暖如春禽车,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刊殉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工殉摔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冗澈。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓钦勘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亚亲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容