# 錨點
????之前提到過,視圖的`center`屬性和圖層的`position`屬性都指定了`anchorPoint`相對于父圖層的位置。圖層的`anchorPoint`通過`position`來控制它的`frame`的位置,你可以認為`anchorPoint`是用來移動圖層的*把柄*。
????默認來說,`anchorPoint`位于圖層的中點,所以圖層的將會以這個點為中心放置。`anchorPoint`屬性并沒有被`UIView`接口暴露出來,這也是視圖的position屬性被叫做“center”的原因。但是圖層的`anchorPoint`可以被移動,比如你可以把它置于圖層`frame`的左上角,于是圖層的內容將會向右下角的`position`方向移動(圖3.3),而不是居中了。

圖3.3 改變`anchorPoint`的效果
????和第二章提到的`contentsRect`和`contentsCenter`屬性類似,`anchorPoint`用*單位坐標*來描述,也就是圖層的相對坐標,圖層左上角是{0, 0},右下角是{1, 1},因此默認坐標是{0.5, 0.5}。`anchorPoint`可以通過指定x和y值小于0或者大于1,使它放置在圖層范圍之外。
????注意在圖3.3中,當改變了`anchorPoint`,`position`屬性保持固定的值并沒有發生改變,但是`frame`卻移動了。
????那在什么場合需要改變`anchorPoint`呢?既然我們可以隨意改變圖層位置,那改變`anchorPoint`不會造成困惑么?為了舉例說明,我們來舉一個實用的例子,創建一個模擬鬧鐘的項目。
????鐘面和鐘表由四張圖片組成(圖3.4),為了簡單說明,我們還是用傳統的方式來裝載和加載圖片,使用四個`UIImageView`實例(當然你也可以用正常的視圖,設置他們圖層的`contents`圖片)。

圖3.4 組成鐘面和鐘表的四張圖片
????鬧鐘的組件通過IB來排列(圖3.5),這些圖片視圖嵌套在一個容器視圖之內,并且自動調整和自動布局都被禁用了。這是因為自動調整會影響到視圖的`frame`,而根據圖3.2的演示,當視圖旋轉的時候,`frame`是會發生改變的,這將會導致一些布局上的失靈。
????我們用`NSTimer`來更新鬧鐘,使用視圖的`transform`屬性來旋轉鐘表(如果你對這個屬性不太熟悉,不要著急,我們將會在第5章“變換”當中詳細說明),具體代碼見清單3.1

圖3.5 在Interface Builder中布局鬧鐘視圖
清單3.1?Clock
~~~
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIImageView *hourHand;
@property (nonatomic, weak) IBOutlet UIImageView *minuteHand;
@property (nonatomic, weak) IBOutlet UIImageView *secondHand;
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//start timer
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
?
//set initial hand positions
[self tick];
}
- (void)tick
{
//convert time to hours, minutes and seconds
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
//calculate hour hand angle //calculate minute hand angle
CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
//calculate second hand angle
CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
//rotate hands
self.hourHand.transform = CGAffineTransformMakeRotation(hoursAngle);
self.minuteHand.transform = CGAffineTransformMakeRotation(minsAngle);
self.secondHand.transform = CGAffineTransformMakeRotation(secsAngle);
}
@end
~~~
????運行項目,看起來有點奇怪(圖3.6),因為鐘表的圖片在圍繞著中心旋轉,這并不是我們期待的一個支點。

圖3.6 鐘面,和不對齊的鐘指針
????你也許會認為可以在Interface Builder當中調整指針圖片的位置來解決,但其實并不能達到目的,因為如果不放在鐘面中間的話,同樣不能正確的旋轉。
????也許在圖片末尾添加一個透明空間也是個解決方案,但這樣會讓圖片變大,也會消耗更多的內存,這樣并不優雅。
????更好的方案是使用`anchorPoint`屬性,我們來在`-viewDidLoad`方法中添加幾行代碼來給每個鐘指針的`anchorPoint`做一些平移(清單3.2),圖3.7顯示了正確的結果。
清單3.2
~~~
- (void)viewDidLoad
{
[super viewDidLoad];
// 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);
// start timer
}
~~~

圖3.7 鐘面,和正確對齊的鐘指針
- Introduction
- 1. 圖層樹
- 1.1 圖層與視圖
- 1.2 圖層的能力
- 1.3 使用圖層
- 1.4 總結
- 2. 寄宿圖
- 2.1 contents屬性
- 2.2 Custom Drawing
- 2.3 總結
- 3. 圖層幾何學
- 3.1 布局
- 3.2 錨點
- 3.3 坐標系
- 3.4 Hit Testing
- 3.5 自動布局
- 3.6 總結
- 4. 視覺效果
- 4.1 圓角
- 4.2 圖層邊框
- 4.3 陰影
- 4.4 圖層蒙板
- 4.5 拉伸過濾
- 4.6 組透明
- 4.7 總結
- 5. 變換
- 5.1 仿射變換
- 5.2 3D變換
- 5.3 固體對象
- 5.4 總結
- 6. 專用圖層
- 6.1 CAShapeLayer
- 6.2 CATextLayer
- 6.3 CATransformLayer
- 6.4 CAGradientLayer
- 6.5 CAReplicatorLayer
- 6.6 CAScrollLayer
- 6.7 CATiledLayer
- 6.8 CAEmitterLayer
- 6.9 CAEAGLLayer
- 6.10 AVPlayerLayer
- 6.11 總結
- 7. 隱式動畫
- 7.1 事務
- 7.2 完成塊
- 7.3 圖層行為
- 7.4 呈現與模型
- 7.5 總結
- 8. 顯式動畫
- 8.1 屬性動畫
- 8.2 動畫組
- 8.3 過渡
- 8.4 在動畫過程中取消動畫
- 8.5 總結
- 9. 圖層時間
- 9.1 CAMediaTiming協議
- 9.2 層級關系時間
- 9.3 手動動畫
- 9.4 總結
- 10. 緩沖
- 10.1 動畫速度
- 10.2 自定義緩沖函數
- 10.3 總結
- 11. 基于定時器的動畫
- 11.1 定時幀
- 11.2 物理模擬
- 12. 性能調優
- 12.1. CPU VS GPU
- 12.2 測量,而不是猜測
- 12.3 Instruments
- 12.4 總結
- 13. 高效繪圖
- 13.1 軟件繪圖
- 13.2 矢量圖形
- 13.3 臟矩形
- 13.4 異步繪制
- 13.5 總結
- 14. 圖像IO
- 14.1 加載和潛伏
- 14.2 緩存
- 14.3 文件格式
- 14.4 總結
- 15. 圖層性能
- 15.1 隱式繪制
- 15.2 離屏渲染
- 15.3 混合和過度繪制
- 15.4 減少圖層數量
- 15.5 總結