转载

CALayer中的anchorPoint

CALayer是封装在UIView中的,为什么要这样封装是为了使代码能够复用在OS X上,UIView上面的界面操作实际上都是在CALayer上完成的,只不过UIView中能够支持app中的各种事件,以及各种touch gesture的响应。在OS X编程中,类似的是NSView,支持一些在PC上才会有的特定的操作。但无论UIView还是NSView,底层的都是CALayer,这样Apple下很多界面的实现都可以统一起来。

在iOS中,UIView封装了很多方法可以让用户直接操作界面,是用户意识不到CALayer的存在,但有时需要用户直接访问UIView的CALayer,因为有些事情在UIView中是无法实现的,比如

1. Shadow,圆角,有色边框

2. 3D变换

3. 非矩形的形状

4. mask bounds

5. 非线性动画等

要描绘一个view的位置信息,有frame,bounds和center;同样,要描绘一个layer(CALayer类型)的位置信息,用的是frame,bounds,position和anchorPoint

在这里,view的center和layer的position意义相同,但它们之间是有关联的,你如果改变了view的frame,相应的layer的frame,position等信息也会同步改变。

如果对一个图形进行旋转操作,那么这个图形的旋转点是按照layer的position来定位的。

现在说说anchorPoint,anchorPoint的默认值是和position相同的,但如果改变anchorPoint的值,图片的显示位置会根据anchorPoint的值重新放置,也就是图片根据你的anchorPoint进行了位移。

其实UIView中,如果用户直接修改frame或center值,也可以实现类似的效果,但为什么还会有一个anchorPoint呢,我们可以用下面的例子来说明anchorPoint的功能是frame或center无法替代的。

我们的例子是实现一个时钟,里面除了表盘还会有时针,分针和秒针,图片如下

CALayer中的anchorPoint

CALayer中的anchorPoint

CALayer中的anchorPoint

CALayer中的anchorPoint

我们先看看习惯的处理办法

- (void)viewDidLoad {     [super viewDidLoad];      [self setupClockFace];      self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f                                                   target:self                                                 selector:@selector(tick)                                                 userInfo:nil                                                  repeats:YES]; }  - (void)setupClockFace {     self.clockFace = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ClockFace"]];     self.hourHand = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"HourHand"]];     self.minuteHand = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MinuteHand"]];     self.secondHand = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SecondHand"]];      CGPoint center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));      self.clockFace.center = center;     self.hourHand.center = center;     self.minuteHand.center = center;     self.secondHand.center = center;      [self.view addSubview:self.clockFace];     [self.view addSubview:self.hourHand];     [self.view addSubview:self.minuteHand];     [self.view addSubview:self.secondHand];      self.view.backgroundColor = [UIColor lightGrayColor]; }  - (void)tick {     // convert time to hours, minutes and seconds     NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];      NSCalendarUnit units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;      NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];      // calculate hour hand angle     CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;      CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;      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); }

这样的代码下显示出来的效果如下

CALayer中的anchorPoint

仔细看发现针的位置是在最中间,但这和我们实际生活中的习惯不是很相同,我们希望指针是按照针尾部进行旋转,我们当然可以把指针的图片做长,另外一部分使用透明的模式,但这样一是浪费存储空间,二是加载的图片更大,更浪费内存。我们为了实现这个效果,可以通过修改anchorPoint的值来实现

- (void)viewDidLoad {     [super viewDidLoad];      [self setupClockFace];      [self adjustClockHands];      self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f                                                   target:self                                                 selector:@selector(tick)                                                 userInfo:nil                                                  repeats:YES]; }  - (void)adjustClockHands {     self.hourHand.layer.anchorPoint = CGPointMake(0.5, 0.9);     self.minuteHand.layer.anchorPoint = CGPointMake(0.5, 0.9);     self.secondHand.layer.anchorPoint = CGPointMake(0.5, 0.9); }

这样操作后,我们得到的效果就成这样了,应该就是我们需要的了

CALayer中的anchorPoint

这里有亮点需要额外注意,第一个就是anchorPoint的单位,他不是point或者pixel值,而是一个unit值,也就是相当于width或者height的比例,所以可以看到CGPointMake(0.5, 0.9)这样的写法;另一个是anchorPoint虽然改变了,但layer的position值并不受影响,在指针transform的时候,仍然是按照position的值进行旋转的(默认position和anchorPoint是相同的)

原文  http://shellcodes.sinaapp.com/articles/509
正文到此结束
Loading...