背景
最近在看《ios核心動畫高階技巧》,這本書的中文版本可以在iOS Core Animation: Advanced Techniques中文譯本
這裡找到,看到圖形幾何學這一章,其中講到的 CALayer
的 anchorPoint
屬性,發現不是很瞭解,所以自己發了點時間做了些研究,做了點簡單的總結,主要涉及到以下主題:
- anchorPoint 是什麼
- anchorPoint 應用場景
本文的DemoDrawDemo
anchorPoint 是什麼
圖層的anchorPoint通過position來控制它的frame的位置,你可以認為anchorPoint是用來移動圖層的把柄。
上面是《ios核心動畫高階技巧》書中對 anchorPoint
的解釋,只看概念可能會不好理解,下面用兩個例子來解釋anchorPoint
的概念。
例一:修改了anchorPoint 對圖層的影響
如圖所示,建立一個Frame為(100, 200, 100, 100)的藍色layer,橙色的layer是修改了anchorPoint為CGPointMake(1, 1)之後的結果
1、分析藍色layer
預設的anchorPoint是(0.5, 0.5),位於layer的中間,position也是位於layer的中間,layer以中心點為定位點,此時positon的意義是 layer的中心點距離父layer的原點的位置是position.x,position.y ,所以最終的frame位置如圖所示為 {{100, 100}, {100, 100}}
2、分析橙色layer anchorPoint是(1, 1),位於layer的右下角,position也是位於layer的右下角,layer以右下角為定位點,此時positon的意義是 layer的右下角距離父layer的原點的位置是position.x,position.y ,所以最終的frame位置如圖所示為 {{50, 50}, {100, 100}}
3、兩個重要的結論
- anchorPoint和position是一一對應的,anchorPoint是相對於layer自身的,是一個單位座標 (0~1, 0~1) ,表示當前layer的定位點是位於layer的什麼位置,定位點決定了layer相對於父layer的關係以及layer的旋轉中心,後面會有旋轉的例子
- 只修改了anchorPoint不會使position變化,但是圖層位置會變化,因為定位點的位置改變了,導致最終Layer的Frame改變了,Frame是最終決定Layer位置的。
例子的程式碼如下:
// anchorPoint 對圖層的影響
layer = [[CALayer alloc] init];
layer.frame = CGRectMake(100, 200, 100, 100);
layer.borderColor = [UIColor blueColor].CGColor;
layer.borderWidth = 1;
layer.anchorPoint = CGPointMake(0.5, 0.5);
[self.view.layer addSublayer:layer];
NSLog(@"layer position = %@, anchorPoint = %@ frame = %@", NSStringFromCGPoint(layer.position), NSStringFromCGPoint(layer.anchorPoint), NSStringFromCGRect(layer.frame));
{
CALayer* copyLayer = [self cloneLayer:layer];
copyLayer.borderColor = [UIColor orangeColor].CGColor;
[self.view.layer addSublayer:copyLayer];
// 預設的anchorPoint位置為(0.5, 0.5),和position是對應的
// 需要移動anchorPoint到layer的右下角,
// 假設認為anchorPoint的位置是固定的,怎樣才能把anchorPoint定位到位置為(1, 1)
// 需要把整個的layer往上和往左移動(layer.width * 0.5)個點才能夠做到
// 這樣會導致frame的origin的變化,也就是layer會往左上角偏移了
// position的值沒有改變,anchorPoint位置是對應的,下面會進行談論
copyLayer.anchorPoint = CGPointMake(1, 1);
NSLog(@"layer position = %@, anchorPoint = %@ frame = %@", NSStringFromCGPoint(copyLayer.position), NSStringFromCGPoint(copyLayer.anchorPoint), NSStringFromCGRect(copyLayer.frame));
// 回到這裡,繼續討論anchorPoint引起的frame的變化而position不變
// anchorPoint是layer定位點(包括旋轉和縮放,是相對於layer自身的,是一個單位座標的點)
// position是和anchorPoint對應的點,是layer相對於父layer的定位點,
// anchorPoint=(0.5, 0.5),layer的中心位置相對於父layer原點的位置為position
// 因為在只修改anchorPoint的情況下不改變position的值,所以:
// anchorPoint=(1, 1),layer的右下角位置相對於父layer原點的位置為position
}
複製程式碼
例二:Frame不變,修改了anchorPoint 對圖層的影響
如圖所示,建立一個Frame為(100, 300, 100, 100)的藍色layer,橙色的layer是修改了anchorPoint為CGPointMake(0, 0)之後但是Frame不變的結果,紅色的layer是修改了anchorPoint為CGPointMake(1, 1)之後但是Frame不變的結果
1、分析橙色Layer
在保持Frame不變的情況下,anchorPoint是(0, 0),位於layer的左上角,position也是位於layer的左上角,layer以左上角為定位點,此時positon的意義是 layer的左上角距離父layer的原點的位置是position.x,position.y ,對layer進行45°的旋轉之後,如圖Layer以左上角做了順時針的45°旋轉。
2、分析紅色Layer
在保持Frame不變的情況下,anchorPoint是(1, 01),位於layer的右下角,position也是位於layer的右下角,layer以右下角為定位點,此時positon的意義是 layer的右下距離父layer的原點的位置是position.x,position.y ,對layer進行45°的旋轉之後,如圖Layer以右下角做了順時針的45°旋轉。
例子的程式碼如下:
// 在Frame不變的情況下討論anchorPoint對position的影響
// 可以這麼認為,position是因變數,anchorPoint是自變數
// anchorPoint和position是一一對應的,是同一個點
layer = [[CALayer alloc] init];
layer.borderColor = [UIColor blueColor].CGColor;
layer.borderWidth = 1;
layer.anchorPoint = CGPointMake(1, 1);
layer.frame = CGRectMake(100, 300, 100, 100);
[self.view.layer addSublayer:layer];
{
CALayer* copylayer = [self cloneLayer:layer];
copylayer.borderColor = [UIColor orangeColor].CGColor;
[self.view.layer addSublayer:copylayer];
// Frame不變,anchorPoint設定到右下角,positon位置也會變到右下角{150, 500}
copylayer.anchorPoint = CGPointMake(1, 1);
copylayer.frame = CGRectMake(100, 300, 100, 100);
NSLog(@"layer.position = %@", NSStringFromCGPoint(copylayer.position));
// 旋轉
copylayer.affineTransform = CGAffineTransformRotate(copylayer.affineTransform, M_PI_4);
}
{
CALayer* copylayer = [self cloneLayer:layer];
copylayer.borderColor = [UIColor orangeColor].CGColor;
[self.view.layer addSublayer:copylayer];
// Frame不變,anchorPoint設定到坐上角,positon位置也會變到坐上角{50, 400}
copylayer.anchorPoint = CGPointMake(0, 0);
copylayer.frame = CGRectMake(100, 300, 100, 100);
NSLog(@"layer.position = %@", NSStringFromCGPoint(copylayer.position));
// 旋轉
copylayer.affineTransform = CGAffineTransformRotate(copylayer.affineTransform, M_PI_4);
}
複製程式碼
anchorPoint 應用場景
例子來自於《ios核心動畫高階技巧》書中國的 時鐘錶盤例子
例子可以在我的git上找到ClockFace
初始的時鐘指標在錶盤中的位置如下:
// 秒針
layer frame:{{124, 77}, {8, 102}} anchorPoint:{0.5, 0.5} position:{128, 128}
// 分針
layer frame:{{118, 75}, {20, 106}} anchorPoint:{0.5, 0.5} position:{128, 128}
// 時針
layer frame:{{113, 81}, {30, 94}} anchorPoint:{0.5, 0.5} position:{128, 128}
複製程式碼
沒有設定anchorPoint的指標走動效果:
根據以上的分析我們知道原因是預設的anchorPoint為{0.5, 0.5},也就是旋轉中心是指標的中心點導致的效果如此,知道原因了修改也不難了,最簡單的做法就是把anchorPoint設定為{0.5, 0.9}即可。
//adjust anchor points
self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
複製程式碼
對應的指標的layer變化:
// 秒針
layer frame:{{124, 36.2}, {8, 102}} anchorPoint:{0.5, 0.89} position:{128, 128}
// 分針
layer frame:{{118, 32.6}, {20, 106}} anchorPoint:{0.5, 0.8} position:{128, 128}
// 時針
layer frame:{{113, 43.4}, {30, 94}} anchorPoint:{0.5, 0.89} position:{128, 128}
複製程式碼
效果如下:
總結
以上是Layer中anchorPoint屬性的一些總結以及一個應用場景,如有不妥之處敬請指教。