默认情况下,CALayer
及其子类的绝大部分标准属性都可以执行动画,无论是添加一个 CAAnimation
到 Layer(显式动画),亦或是为属性指定一个动作然后修改它(隐式动画)。
但有时候我们希望能同时为好几个属性添加动画,使它们看起来像是一个动画一样;或者,我们需要执行的动画不能通过使用标准 Layer 属性动画来实现。
在本文中,我们将讨论如何子类化 CALayer
并添加我们自己的属性,以便比较容易地创建那些如果以其他方式实现起来会很麻烦的动画效果。
一般说来,我们希望添加到 CALayer
的子类上的可动画属性有三种类型:
- 能间接动画 Layer (或其子类)的一个或多个标准属性的属性。
- 能触发 Layer 背后的图像(即
contents
属性)重绘的属性。 - 不涉及 Layer 重绘或对任何已有属性执行动画的属性。
间接属性动画
能间接修改其它标准 Layer 属性的自定义属性是这些选项中最简单的。它们仅仅只是自定义 setter 方法。然后将它们的输入转换为适用于创建动画的一个或多个不同的值。
如果被我们设置的属性已经预设好标准动画,那我们完全不需要编写任何实际的动画代码,因为我们修改这些属性后,它们就会继承任何被配置在当前 CATransaction
上的动画设置,并且自动执行动画。
换句话说,即使 CALayer
不知道如何对我们自定义的属性进行动画,它依然能对因自定义属性被改变而引起的其它可见副作用进行动画,而这恰好就是我们所需要的。
为了演示这种方法,让我们来创建一个简单的模拟时钟,之后我们可以使用被声明为 NSDate
类型 time
属性来设置它的时间。我会将从创建一个静态的时钟面盘开始。这个时钟包含三个 CAShapeLayer
实例 —— 一个用于时钟面盘的圆形 Layer 和两个用于时针和分针的长方形 Sublayer。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
@interface ClockFace: CAShapeLayer @property (nonatomic, strong) NSDate *time; @end @interface ClockFace () // 私有属性 @property (nonatomic, strong) CAShapeLayer *hourHand; @property (nonatomic, strong) CAShapeLayer *minuteHand; @end @implementation ClockFace - (id)init { if ((self = [super init])) { self.bounds = CGRectMake(0, 0, 200, 200); self.path = [UIBezierPath bezierPathWithOvalInRect:self.bounds].CGPath; self.fillColor = [UIColor whiteColor].CGColor; self.strokeColor = [UIColor blackColor].CGColor; self.lineWidth = 4; self.hourHand = [CAShapeLayer layer]; self.hourHand.path = [UIBezierPath bezierPathWithRect:CGRectMake(-2, -70, 4, 70)].CGPath; self.hourHand.fillColor = [UIColor blackColor].CGColor; self.hourHand.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); [self addSublayer:self.hourHand]; self.minuteHand = [CAShapeLayer layer]; self.minuteHand.path = [UIBezierPath bezierPathWithRect:CGRectMake(-1, -90, 2, 90)].CGPath; self.minuteHand.fillColor = [UIColor blackColor].CGColor; self.minuteHand.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); [self addSublayer:self.minuteHand]; } return self; } @end |
同时我们要设置一个包含 UIDatePicker
的基本的 View Controller,这样我们就能测试我们的 Layer (日期选择器在 Storyboard 里设置)了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
@interface ViewController () @property (nonatomic, strong) IBOutlet UIDatePicker *datePicker; @property (nonatomic, strong) ClockFace *clockFace; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad];idLoad { [super viewDidLoad];。
但有时候我们希望能同时为好几个属性添加动画,使它们看起来像是一个动画一样;或者,我们需要执行的动画不能通过使用标准 Layer 属性动画来实现。 在本文中,我们将讨论如何子类化 一般说来,我们希望添加到
间接属性动画能间接修改其它标准 Layer 属性的自定义属性是这些选项中最简单的。它们仅仅只是自定义 setter 方法。然后将它们的输入转换为适用于创建动画的一个或多个不同的值。 如果被我们设置的属性已经预设好标准动画,那我们完全不需要编写任何实际的动画代码,因为我们修改这些属性后,它们就会继承任何被配置在当前 换句话说,即使 为了演示这种方法,让我们来创建一个简单的模拟时钟,之后我们可以使用被声明为
同时我们要设置一个包含
|