3.2 锚点

最后更新于:2022-04-01 10:08:25

# 锚点     之前提到过,视图的`center`属性和图层的`position`属性都指定了`anchorPoint`相对于父图层的位置。图层的`anchorPoint`通过`position`来控制它的`frame`的位置,你可以认为`anchorPoint`是用来移动图层的*把柄*。     默认来说,`anchorPoint`位于图层的中点,所以图层的将会以这个点为中心放置。`anchorPoint`属性并没有被`UIView`接口暴露出来,这也是视图的position属性被叫做“center”的原因。但是图层的`anchorPoint`可以被移动,比如你可以把它置于图层`frame`的左上角,于是图层的内容将会向右下角的`position`方向移动(图3.3),而不是居中了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-24_567bc1ee649bd.png) 图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`图片)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-24_567bc1ee82e2b.png) 图3.4 组成钟面和钟表的四张图片     闹钟的组件通过IB来排列(图3.5),这些图片视图嵌套在一个容器视图之内,并且自动调整和自动布局都被禁用了。这是因为自动调整会影响到视图的`frame`,而根据图3.2的演示,当视图旋转的时候,`frame`是会发生改变的,这将会导致一些布局上的失灵。     我们用`NSTimer`来更新闹钟,使用视图的`transform`属性来旋转钟表(如果你对这个属性不太熟悉,不要着急,我们将会在第5章“变换”当中详细说明),具体代码见清单3.1 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-24_567bc1eeab49d.png) 图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),因为钟表的图片在围绕着中心旋转,这并不是我们期待的一个支点。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-24_567bc1eeeb615.png) 图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 } ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-24_567bc1ef293b2.png) 图3.7 钟面,和正确对齐的钟指针
';