iOS 理解position與anchorPoint

前言

相信很多剛接觸CALayer的人都會(huì)遇到一下幾個(gè)麻煩:
1. 為什么修改anchorPoint會(huì)移動(dòng)layer的位置烘豹?
2. CALayer的position點(diǎn)是哪一點(diǎn)呢?
3. anchorPoint與position有什么關(guān)系较锡?
今天我們就來(lái)討論一下這些問(wèn)題

關(guān)系

每一個(gè)UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個(gè)CALayer, UIView有frame皿曲、bounds和center三個(gè)屬性,CALayer也有類似的屬性,分別為frame、bounds、position其障、anchorPoint。frame和bounds比較好理解涂佃,bounds可以視為x坐標(biāo)和y坐標(biāo)都為0的frame励翼,那positionanchorPoint是什么呢巡李?先看看兩者的原型抚笔,可知都是CGPoint點(diǎn)。

@property CGPoint position
@property CGPoint anchorPoint

anchorPoint

從一個(gè)例子開(kāi)始入手吧侨拦,想象一下殊橙,把一張A4白紙用圖釘訂在書(shū)桌上,如果訂得不是很緊的話狱从,白紙就可以沿順時(shí)針或逆時(shí)針?lè)较驀@圖釘旋轉(zhuǎn)膨蛮,這時(shí)候圖釘就起著支點(diǎn)的作用。我們要解釋的anchorPoint就相當(dāng)于白紙上的圖釘季研,它主要的作用就是用來(lái)作為變換的支點(diǎn)敞葛,旋轉(zhuǎn)就是一種變換,類似的還有平移与涡、縮放惹谐。

繼續(xù)擴(kuò)展,很明顯驼卖,白紙的旋轉(zhuǎn)形態(tài)隨圖釘?shù)奈恢貌煌煌奔。瑘D釘訂在白紙的正中間與左上角時(shí)分別造就了兩種旋轉(zhuǎn)形態(tài),這是由圖釘(anchorPoint)的位置決定的酌畜。如何衡量圖釘(anchorPoint)在白紙中的位置呢怎囚?在iOS中,anchorPoint點(diǎn)的值是用一種相對(duì)bounds的比例值來(lái)確定的桥胞,在白紙的左上角恳守、右下角,anchorPoint分為為(0,0), (1, 1)贩虾,也就是說(shuō)anchorPoint是在單元坐標(biāo)空間(同時(shí)也是左手坐標(biāo)系)中定義的催烘。類似地,可以得出在白紙的中心點(diǎn)缎罢、左下角和右上角的anchorPoint為(0.5,0.5), (0,1), (1,0)颗圣。

然后再來(lái)看下面兩張圖喳钟,注意圖中分iOS與MacOS,因?yàn)閮烧叩淖鴺?biāo)系不相同在岂,iOS使用左手坐標(biāo)系,坐標(biāo)原點(diǎn)在左上角蛮寂,MacOS使用右手坐標(biāo)系蔽午,原點(diǎn)在左下角,我們看iOS部分即可酬蹋。

圖1.png
圖2.png

像UIView有superView與subView的概念一樣及老,CALayer也有superLayer與layer的概念,前面說(shuō)到的白紙和圖中的矩形可以理解為layer范抓,書(shū)桌和圖中矩形以外的坐標(biāo)系可以理解成superLayer骄恶。如果各自以左上角為原點(diǎn),則在圖中有相對(duì)的兩個(gè)坐標(biāo)空間匕垫。

position

在圖1中僧鲁,anchorPoint有(0.5,0.5)和(0,0)兩種情況,分別為矩形的中心點(diǎn)與原點(diǎn)象泵。那么寞秃,這兩個(gè)anchorPoint在superLayer中的實(shí)際位置分別為多少呢?簡(jiǎn)單計(jì)算一下就可以得到(100, 100)和(40, 60)偶惠,把這兩個(gè)值分別與各自的position值比較春寿,發(fā)現(xiàn)完全一致,該不會(huì)是巧合忽孽?

這時(shí)候可以大膽猜測(cè)一下绑改,position是不是就是anchorPoint在superLayer中的位置呢?答案是確定的兄一,更確切地說(shuō)厘线,position是layer中的anchorPoint點(diǎn)在superLayer中的位置坐標(biāo)。因此可以說(shuō), position點(diǎn)是相對(duì)suerLayer的瘾腰,anchorPoint點(diǎn)是相對(duì)layer的皆的,兩者是相對(duì)不同的坐標(biāo)空間的一個(gè)重合點(diǎn)。

再來(lái)看看position的原始定義: The layer’s position in its superlayer’s coordinate space蹋盆。
中文可以理解成為position是layer相對(duì)superLayer坐標(biāo)空間的位置费薄,很顯然,這里的位置是根據(jù)anchorPoint來(lái)確定的栖雾。

圖2中是矩形沿不同的anchorPoint點(diǎn)旋轉(zhuǎn)的形態(tài)楞抡,這就是類似于剛才講的圖釘訂在白紙的正中間與左上角時(shí)分別造就了兩種旋轉(zhuǎn)形態(tài)。

anchorPoint析藕、position召廷、frame之間的關(guān)系

anchorPoint的默認(rèn)值為(0.5,0.5),也就是anchorPoint默認(rèn)在layer的中心點(diǎn)。默認(rèn)情況下竞慢,使用addSublayer函數(shù)添加layer時(shí)先紫,如果已知layer的frame值,根據(jù)上面的結(jié)論筹煮,那么position的值便可以用下面的公式計(jì)算:

position.x = frame.origin.x + 0.5 * bounds.size.width遮精;  
position.y = frame.origin.y + 0.5 * bounds.size.height; 

里面的0.5是因?yàn)閍nchorPoint取默認(rèn)值败潦,更通用的公式應(yīng)該是下面的:

position.x = frame.origin.x + anchorPoint.x * bounds.size.width本冲;  
position.y = frame.origin.y + anchorPoint.y * bounds.size.height;

下面再來(lái)看另外兩個(gè)問(wèn)題劫扒,如果單方面修改layer的position位置檬洞,會(huì)對(duì)anchorPoint有什么影響呢?修改anchorPoint又如何影響position呢沟饥?
根據(jù)代碼測(cè)試添怔,兩者互不影響,受影響的只會(huì)是frame.origin闷板,也就是layer坐標(biāo)原點(diǎn)相對(duì)superLayer會(huì)有所改變澎灸。換句話說(shuō),frame.origin由position和anchorPoint共同決定遮晚,上面的公式可以變換成下面這樣的

frame.origin.x = position.x - anchorPoint.x * bounds.size.width性昭;  
frame.origin.y = position.y - anchorPoint.y * bounds.size.height;

這就解釋了為什么修改anchorPoint會(huì)移動(dòng)layer县遣,因?yàn)閜osition不受影響糜颠,只能是frame.origin做相應(yīng)的改變,因而會(huì)移動(dòng)layer萧求。

應(yīng)用

在Apple doc對(duì)frame的描述中有這么一句話:

Layers have an implicit frame that is a function of the position, bounds, anchorPoint, and transform properties.

可以看到我們推導(dǎo)的公式基本符合這段描述其兴,只不過(guò)還缺少了transform,加上transform的話就比較復(fù)雜夸政,這里就不展開(kāi)講了元旬。

Apple doc中還有一句描述是這樣的:

When you specify the frame of a layer, position is set relative to the anchor point. When you specify the position of the layer, bounds is set relative to the anchor point.

大意是:當(dāng)你設(shè)置圖層的frame屬性的時(shí)候,position根據(jù)錨點(diǎn)(anchorPoint)的值來(lái)確定守问,而當(dāng)你設(shè)置圖層的position屬性的時(shí)候匀归,bounds會(huì)根據(jù)錨點(diǎn)(anchorPoint)來(lái)確定。

這段翻譯的上半句根據(jù)前面的公式容易理解耗帕,后半句可能就有點(diǎn)令人迷惑了穆端,當(dāng)修改position時(shí),bounds的width與height會(huì)隨之修改嗎仿便?其實(shí),position是點(diǎn)体啰,bounds是矩形攒巍,根據(jù)錨點(diǎn)(anchorPoint)來(lái)確定的只是它們的位置,而不是內(nèi)部屬性荒勇。所以柒莉,上面這段英文這么翻譯就容易理解了:

當(dāng)你設(shè)置圖層的frame屬性的時(shí)候,position點(diǎn)的位置(也就是position坐標(biāo))根據(jù)錨點(diǎn)(anchorPoint)的值來(lái)確定枕屉,而當(dāng)你設(shè)置圖層的position屬性的時(shí)候常柄,bounds的位置(也就是frame的orgin坐標(biāo))會(huì)根據(jù)錨點(diǎn)(anchorPoint)來(lái)確定。

在實(shí)際情況中搀擂,可能還有這樣一種需求,我需要修改anchorPoint卷玉,但又不想要移動(dòng)layer也就是不想修改frame.origin哨颂,那么根據(jù)前面的公式,就需要position做相應(yīng)地修改相种。簡(jiǎn)單地推導(dǎo)威恼,可以得到下面的公式:

positionNew.x = positionOld.x + (anchorPointNew.x - anchorPointOld.x)  * bounds.size.width  
positionNew.y = positionOld.y + (anchorPointNew.y - anchorPointOld.y)  * bounds.size.height

但是在實(shí)際使用沒(méi)必要這么麻煩。修改anchorPoint而不想移動(dòng)layer寝并,在修改anchorPoint后再重新設(shè)置一遍frame就可以達(dá)到目的箫措,這時(shí)position就會(huì)自動(dòng)進(jìn)行相應(yīng)的改變。寫(xiě)成函數(shù)就是下面這樣的:

- (void) setAnchorPoint:(CGPoint)anchorpoint forView:(UIView *)view{
  CGRect oldFrame = view.frame;
  view.layer.anchorPoint = anchorpoint;
  view.frame = oldFrame;
}

總結(jié)

1. position是layer中的anchorPoint在superLayer中的位置坐標(biāo)衬潦。
2. 互不影響原則:?jiǎn)为?dú)修改position與anchorPoint中任何一個(gè)屬性都不影響另一個(gè)屬性斤蔓。
3. frame、position與anchorPoint有以下關(guān)系:

frame.origin.x = position.x - anchorPoint.x * bounds.size.width镀岛;  
frame.origin.y = position.y - anchorPoint.y * bounds.size.height弦牡;

第2條的互不影響原則還可以這樣理解:position與anchorPoint是處于不同坐標(biāo)空間中的重合點(diǎn),修改重合點(diǎn)在一個(gè)坐標(biāo)空間的位置不影響該重合點(diǎn)在另一個(gè)坐標(biāo)空間中的位置漂羊。

參考

Wonderffee's Blog:徹底理解position與anchorPoint

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驾锰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子走越,更是在濱河造成了極大的恐慌椭豫,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旨指,死亡現(xiàn)場(chǎng)離奇詭異赏酥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)淤毛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)今缚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人低淡,你說(shuō)我怎么就攤上這事姓言∷蚕睿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵何荚,是天一觀的道長(zhǎng)囱淋。 經(jīng)常有香客問(wèn)我,道長(zhǎng)餐塘,這世上最難降的妖魔是什么妥衣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮戒傻,結(jié)果婚禮上税手,老公的妹妹穿的比我還像新娘。我一直安慰自己需纳,他們只是感情好芦倒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著不翩,像睡著了一般兵扬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上口蝠,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天器钟,我揣著相機(jī)與錄音,去河邊找鬼妙蔗。 笑死傲霸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的灭必。 我是一名探鬼主播狞谱,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼禁漓!你這毒婦竟也來(lái)了跟衅?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤播歼,失蹤者是張志新(化名)和其女友劉穎伶跷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體秘狞,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叭莫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烁试。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雇初。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖减响,靈堂內(nèi)的尸體忽然破棺而出靖诗,到底是詐尸還是另有隱情郭怪,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布刊橘,位于F島的核電站鄙才,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏促绵。R本人自食惡果不足惜攒庵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望败晴。 院中可真熱鬧浓冒,春花似錦、人聲如沸尖坤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)糖驴。三九已至,卻和暖如春佛致,著一層夾襖步出監(jiān)牢的瞬間贮缕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工俺榆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留感昼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓罐脊,卻偏偏與公主長(zhǎng)得像定嗓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萍桌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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