iOS:重識Transform和frame

關(guān)于frame

  • frame是一個(gè)復(fù)合屬性,由center、bounds和transform共同計(jì)算而來复局。
  • transform改變,frame會(huì)受到影響粟判,但是center和bounds不會(huì)受到影響亿昏。也就是你使用transform來縮放,bounds是不會(huì)變的档礁。那么由center和bounds計(jì)算得到的frame是永遠(yuǎn)保持transform為identity時(shí)的狀態(tài)角钩。這也是為什么把transform設(shè)為identity后,view會(huì)回歸到最初狀態(tài)。

關(guān)于transform的計(jì)算

當(dāng)你使用view.transform = xxx時(shí)候递礼,它到底是怎么起作用的惨险?首先,它是一個(gè)矩陣脊髓,使用矩陣乘法辫愉,對view的frame進(jìn)行變換,得到新的變換将硝,那么這個(gè)邏輯是怎樣的恭朗?

  • 它是針對父視圖坐標(biāo)的。
  • 它是針對view的初始中心為坐標(biāo)的:“初始”是指transform值為identity時(shí)的狀態(tài)依疼,即沒有任何的縮放痰腮、平移或旋轉(zhuǎn);“中心”默認(rèn)是view方塊的中心律罢,但實(shí)際是anchorPoint膀值。

那么viewA.transform = myTransform這么一段代碼就等價(jià)于:

  1. 把父視圖坐標(biāo)系的原點(diǎn)移動(dòng)到view的中心,計(jì)算中心坐標(biāo)系的frame,得到frame1:
CGRect frame1 = CGRectMake(
-originalFrame2.size.width/2.0,
-originalFrame2.size.height/2.0, 
originalFrame2.size.width, 
originalFrame2.size.height);
  1. 以坐標(biāo)系改變后的frame(即centerFrame)計(jì)算弟翘,使用矩陣乘法應(yīng)用transform,得到frame2:CGRect frame2 = CGRectApplyAffineTransform(frame2, myTransform)

  2. 再把結(jié)果轉(zhuǎn)回原父視圖坐標(biāo)系,得到frame3:

CGRect frame3 = CGRectMake(
frame2.origin.x + CGRectGetMidX(originalFrame), 
frame2.origin.y + CGRectGetMidY(originalFrame),
frame2.size.width, 
frame2.size.height);

這么做的好處便是在縮放的時(shí)候虫腋,是針對view當(dāng)前位置的,這樣view的原點(diǎn)不會(huì)改變稀余,也就是縮放只會(huì)產(chǎn)生縮放的效果悦冀,而不會(huì)產(chǎn)生平移。假設(shè)使用父視圖原點(diǎn)睛琳,frame為{10,20,100,100},縮放后變成{5,10,50,50},那么frame不僅變小了盒蟆,也和原點(diǎn)更近了。

怎么計(jì)算兩個(gè)frame之間的transform

給你一個(gè)view和一個(gè)目標(biāo)frame师骗,求一個(gè)transform历等,使得把這個(gè)transform給view后,view的frame等于目標(biāo)frame辟癌。

在處理動(dòng)畫的時(shí)候會(huì)用到寒屯。

因?yàn)榭s放會(huì)影響平移,而平移卻不會(huì)影響縮放黍少,所以先平移到中心和目標(biāo)frame一致寡夹,然后縮放。

平移的距離就是兩個(gè)center的差值厂置,縮放比例的就是兩個(gè)frame的邊長之比菩掏。

即:

-(CGAffineTransform)transformFromRect:(CGRect)fromRect toRect:(CGRect)toRect{
     CGAffineTransform moveTrans = CGAffineTransformMakeTranslation(CGRectGetMidX(toRect) - CGRectGetMidX(fromRect), CGRectGetMidY(toRect) - CGRectGetMidY(fromRect));
   
     CGAffineTransform scaleTrans = CGAffineTransformMakeScale(toRect.size.width / fromRect.size.width, toRect.size.height / fromRect.size.height);
   
     //右邊先執(zhí)行
     return CGAffineTransformConcat(scaleTrans, moveTrans);
}

為什么使用transform動(dòng)畫而不是設(shè)置frame?

如果transform里包含了旋轉(zhuǎn),那么計(jì)算出來的frame就沒有意義了昵济,因?yàn)閒rame總是描述一個(gè)“擺正的”方塊智绸,而旋轉(zhuǎn)后的方塊是沒法描述的野揪。

但對于只有平移和縮放,用上述邏輯是可以計(jì)算的瞧栗。我在做一個(gè)過場動(dòng)畫的時(shí)候用到了這個(gè)斯稳,動(dòng)畫是類似系統(tǒng)相冊那樣從一個(gè)小圖逐漸放大到全屏,所以你擁有的信息是一個(gè)起始的frame沼溜,以這個(gè)為開始動(dòng)畫平挑。

我嘗試了通過直接設(shè)置frame來執(zhí)行動(dòng)畫,但發(fā)現(xiàn)效果糟糕系草,因?yàn)閯?dòng)畫雖然有一個(gè)過程,但其實(shí)從動(dòng)畫一開始唆涝,frame就已經(jīng)修改了找都。如果直接設(shè)置frame,那么開始的時(shí)候廊酣,子視圖就會(huì)按變化后的frame來重新布局能耻,而不是跟隨父視圖一起慢慢變化

動(dòng)畫是渲染呈現(xiàn)上的樣子亡驰,而實(shí)際的數(shù)值卻是另一種樣子晓猛,在core animation里有模型樹呈現(xiàn)樹的區(qū)別。

舉個(gè)例子:


設(shè)置frame的動(dòng)畫
設(shè)置transform的動(dòng)畫

測試view是灰色凡辱,它有一個(gè)子視圖是紅色:

-(void)layoutSubviews{
    innerView.frame = CGRectMake(10, 10, self.frame.size.width-20, self.frame.size.height-20);
}

內(nèi)部的view保持和父視圖10的邊距戒职。所以看第一個(gè)動(dòng)畫,在剛開始的時(shí)候透乾,紅色的view就變成了動(dòng)畫結(jié)束時(shí)的大小洪燥,而第二個(gè)動(dòng)畫使用transform變換,其實(shí)layoutSubviews并沒有調(diào)用乳乌,但是卻得到了想要的效果捧韵。貌似transform只是影響了view的渲染,而且是影響了整個(gè)的子視圖數(shù)汉操,就像把這個(gè)view當(dāng)做一張圖片一樣縮小了再来,而內(nèi)部卻不需要重新布局。

使用transform效果更好磷瘤,那么就要從一個(gè)初始frame計(jì)算得到transform芒篷,使得賦值給view后,它就是到初始frame的位置膀斋。所以就有了上面的transform計(jì)算梭伐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仰担,隨后出現(xiàn)的幾起案子糊识,更是在濱河造成了極大的恐慌绩社,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赂苗,死亡現(xiàn)場離奇詭異愉耙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拌滋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門朴沿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人败砂,你說我怎么就攤上這事赌渣。” “怎么了昌犹?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵坚芜,是天一觀的道長。 經(jīng)常有香客問我斜姥,道長鸿竖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任铸敏,我火速辦了婚禮缚忧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杈笔。我一直安慰自己闪水,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布桩撮。 她就那樣靜靜地躺著敦第,像睡著了一般。 火紅的嫁衣襯著肌膚如雪店量。 梳的紋絲不亂的頭發(fā)上芜果,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機(jī)與錄音融师,去河邊找鬼右钾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛旱爆,可吹牛的內(nèi)容都是我干的舀射。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼怀伦,長吁一口氣:“原來是場噩夢啊……” “哼脆烟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起房待,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤邢羔,失蹤者是張志新(化名)和其女友劉穎驼抹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拜鹤,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡框冀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敏簿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片明也。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖惯裕,靈堂內(nèi)的尸體忽然破棺而出温数,到底是詐尸還是另有隱情,我是刑警寧澤轻猖,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布帆吻,位于F島的核電站,受9級特大地震影響咙边,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜次员,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一败许、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淑蔚,春花似錦市殷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至带迟,卻和暖如春音羞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仓犬。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工嗅绰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搀继。 一個(gè)月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓窘面,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叽躯。 傳聞我的和親對象是個(gè)殘疾皇子财边,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

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

  • Core Animation其實(shí)是一個(gè)令人誤解的命名。你可能認(rèn)為它只是用來做動(dòng)畫的点骑,但實(shí)際上它是從一個(gè)叫做Laye...
    小貓仔閱讀 3,728評論 1 4
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果酣难,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜谍夭,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,115評論 5 13
  • Core Animation基礎(chǔ) Core Animation 利用了硬件加速和架構(gòu)上的優(yōu)化來實(shí)現(xiàn)快速渲染和實(shí)時(shí)動(dòng)...
    獨(dú)木舟的木閱讀 1,542評論 0 3
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果鲸鹦,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜慧库,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,514評論 6 30
  • 曾經(jīng)有人這么說過馋嗜,在iphone里你看到的齐板,摸到的,都是UIView葛菇,所以UIView在iphone開發(fā)里具有非常...
    我是一只攻城獅_ifYou閱讀 637評論 0 2