故而时间能够被随机基于三个图层或许一段动画的类控制,所以时间能够被肆意基于1个图层大概一段动画的类控制

#CAMediaTiming`协议

#CAMediaTiming`协议

CAMediaTiming协和式飞机定义了在一段动画内用来决定逝去岁月的性质的聚合,CALayerCAAnimation都落到实处了那个体协会议,所以时间能够被轻易基于贰个图层只怕一段动画的类控制。

CAMediaTiming商业事务定义了在一段动画内用来控制逝去岁月的质量的集纳,CALayerCAAnimation都达成了那些体协会议,所以时间足以被任意基于三个图层或许一段动画的类控制。

没完没了和重新

小编们在第柒章“显式动画”中简单关联过durationCAMediaTiming的习性之一),duration是一个CFTimeInterval的类型(类似于NSTimeInterval的一种双精度浮点类型),对即将进行的卡通的一回迭代钦点了光阴。

这里的贰遍迭代是何许看头啊?CAMediaTiming其它还有壹本性质叫做repeatCount,代表动画重复的迭代次数。假如duration是2,repeatCount设为3.5(七个半迭代),那么完整的卡通片时间长度将是7秒。

durationrepeatCount私下认可都以0。但那不意味着动画时间长度为0秒,或然0次,那里的0仅仅代表了“私下认可”,也正是0.25秒和贰次,你能够用一个回顾的测试来尝试为那八个属性赋三个值,如清单9.1,图9.1体现了程序的结果。

清单9.1 测试durationrepeatCount

澳门金冠网站主页 1澳门金冠网站主页 2

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 @property (nonatomic, weak) IBOutlet UITextField *durationField;
 5 @property (nonatomic, weak) IBOutlet UITextField *repeatField;
 6 @property (nonatomic, weak) IBOutlet UIButton *startButton;
 7 @property (nonatomic, strong) CALayer *shipLayer;
 8 
 9 @end
10 
11 @implementation ViewController
12 
13 - (void)viewDidLoad
14 {
15     [super viewDidLoad];
16     //add the ship
17     self.shipLayer = [CALayer layer];
18     self.shipLayer.frame = CGRectMake(0, 0, 128, 128);
19     self.shipLayer.position = CGPointMake(150, 150);
20     self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
21     [self.containerView.layer addSublayer:self.shipLayer];
22 }
23 
24 - (void)setControlsEnabled:(BOOL)enabled
25 {
26     for (UIControl *control in @[self.durationField, self.repeatField, self.startButton]) {
27         control.enabled = enabled;
28         control.alpha = enabled? 1.0f: 0.25f;
29     }
30 }
31 
32 - (IBAction)hideKeyboard
33 {
34     [self.durationField resignFirstResponder];
35     [self.repeatField resignFirstResponder];
36 }
37 
38 - (IBAction)start
39 {
40     CFTimeInterval duration = [self.durationField.text doubleValue];
41     float repeatCount = [self.repeatField.text floatValue];
42     //animate the ship rotation
43     CABasicAnimation *animation = [CABasicAnimation animation];
44     animation.keyPath = @"transform.rotation";
45     animation.duration = duration;
46     animation.repeatCount = repeatCount;
47     animation.byValue = @(M_PI * 2);
48     animation.delegate = self;
49     [self.shipLayer addAnimation:animation forKey:@"rotateAnimation"];
50     //disable controls
51     [self setControlsEnabled:NO];
52 }
53 
54 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
55 {
56     //reenable controls
57     [self setControlsEnabled:YES];
58 }
59 
60 @end

View Code

澳门金冠网站主页 3

图9.1 演示durationrepeatCount的测试程序

创制重复动画的另一种艺术是选取repeatDuration性能,它让动画重复3个点名的光阴,而不是点排行数。你甚至设置三个名为autoreverses的属性(BOOL类型)在每回间隔交替循环进程中机动回看。那对于播放一段连接非循环的动画很有用,例如打开一扇门,然后关上它(图9.2)。

澳门金冠网站主页 4

 

图9.2 摆动门的动画

对门进行摆动的代码见清单9.2。大家用了autoreverses来使门在开辟后自动关闭,在此地大家把repeatDuration设置为INFINITY,于是动画无限循环播放,设置repeatCountINFINITY也有同等的成效。注意repeatCountrepeatDuration想必会相互争辩,所以你一旦对里面四个点名非零值。对八个属性都设置非0值的行为没有被定义。

清单9.2 使用autoreverses质量实现门的忽悠

 

澳门金冠网站主页 5澳门金冠网站主页 6

@interface ViewController ()

@property (nonatomic, weak) UIView *containerView;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //add the door
    CALayer *doorLayer = [CALayer layer];
    doorLayer.frame = CGRectMake(0, 0, 128, 256);
    doorLayer.position = CGPointMake(150 - 64, 150);
    doorLayer.anchorPoint = CGPointMake(0, 0.5);
    doorLayer.contents = (__bridge id)[UIImage imageNamed: @"Door.png"].CGImage;
    [self.containerView.layer addSublayer:doorLayer];
    //apply perspective transform
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    self.containerView.layer.sublayerTransform = perspective;
    //apply swinging animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation.y";
    animation.toValue = @(-M_PI_2);
    animation.duration = 2.0;
    animation.repeatDuration = INFINITY;
    animation.autoreverses = YES;
    [doorLayer addAnimation:animation forKey:nil];
}

@end

View Code

绵绵和再度

作者们在第⑦章“显式动画”中简易关联过durationCAMediaTiming的习性之一),duration是一个CFTimeInterval的类型(类似于NSTimeInterval的一种双精度浮点类型),对即将进行的动画片的1回迭代钦赐了光阴。

这里的三回迭代是哪些看头啊?CAMediaTiming此外还有壹天质量叫做repeatCount,代表动画重复的迭代次数。要是duration是2,repeatCount设为3.5(多个半迭代),那么完整的动画片时间长度将是7秒。

durationrepeatCount暗中同意都是0。但那不意味着动画时间长度为0秒,或许0次,那里的0仅仅代表了“默许”,也正是0.25秒和三回,你能够用一个不难的测试来品尝为那四个属性赋七个值,如清单9.1,图9.1显示了程序的结果。

清单9.1 测试durationrepeatCount

澳门金冠网站主页 7澳门金冠网站主页 8

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 @property (nonatomic, weak) IBOutlet UITextField *durationField;
 5 @property (nonatomic, weak) IBOutlet UITextField *repeatField;
 6 @property (nonatomic, weak) IBOutlet UIButton *startButton;
 7 @property (nonatomic, strong) CALayer *shipLayer;
 8 
 9 @end
10 
11 @implementation ViewController
12 
13 - (void)viewDidLoad
14 {
15     [super viewDidLoad];
16     //add the ship
17     self.shipLayer = [CALayer layer];
18     self.shipLayer.frame = CGRectMake(0, 0, 128, 128);
19     self.shipLayer.position = CGPointMake(150, 150);
20     self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
21     [self.containerView.layer addSublayer:self.shipLayer];
22 }
23 
24 - (void)setControlsEnabled:(BOOL)enabled
25 {
26     for (UIControl *control in @[self.durationField, self.repeatField, self.startButton]) {
27         control.enabled = enabled;
28         control.alpha = enabled? 1.0f: 0.25f;
29     }
30 }
31 
32 - (IBAction)hideKeyboard
33 {
34     [self.durationField resignFirstResponder];
35     [self.repeatField resignFirstResponder];
36 }
37 
38 - (IBAction)start
39 {
40     CFTimeInterval duration = [self.durationField.text doubleValue];
41     float repeatCount = [self.repeatField.text floatValue];
42     //animate the ship rotation
43     CABasicAnimation *animation = [CABasicAnimation animation];
44     animation.keyPath = @"transform.rotation";
45     animation.duration = duration;
46     animation.repeatCount = repeatCount;
47     animation.byValue = @(M_PI * 2);
48     animation.delegate = self;
49     [self.shipLayer addAnimation:animation forKey:@"rotateAnimation"];
50     //disable controls
51     [self setControlsEnabled:NO];
52 }
53 
54 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
55 {
56     //reenable controls
57     [self setControlsEnabled:YES];
58 }
59 
60 @end

View Code

澳门金冠网站主页 9

图9.1 演示durationrepeatCount的测试程序

开创重复动画的另一种方法是利用repeatDuration属性,它让动画重复三个内定的时刻,而不是点排名数。你居然设置一个叫做autoreverses的品质(BOOL类型)在历次间隔交替循环进程中机动回看。那对于播放一段连接非循环的卡通片很有用,例如打开一扇门,然后关上它(图9.2)。

澳门金冠网站主页 10

 

图9.2 摆动门的动画

对门举办摆动的代码见清单9.2。大家用了autoreverses来使门在打开后自行关闭,在那里大家把repeatDuration设置为INFINITY,于是动画无限循环播放,设置repeatCountINFINITY也有一样的效益。注意repeatCountrepeatDuration可能会相互争论,所以你一旦对里面一个钦点非零值。对五个属性都安装非0值的一言一动尚未被定义。

清单9.2 使用autoreverses属性完毕门的忽悠

 

澳门金冠网站主页 11澳门金冠网站主页 12

@interface ViewController ()

@property (nonatomic, weak) UIView *containerView;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //add the door
    CALayer *doorLayer = [CALayer layer];
    doorLayer.frame = CGRectMake(0, 0, 128, 256);
    doorLayer.position = CGPointMake(150 - 64, 150);
    doorLayer.anchorPoint = CGPointMake(0, 0.5);
    doorLayer.contents = (__bridge id)[UIImage imageNamed: @"Door.png"].CGImage;
    [self.containerView.layer addSublayer:doorLayer];
    //apply perspective transform
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    self.containerView.layer.sublayerTransform = perspective;
    //apply swinging animation
    CABasicAnimation *animation = [CABasicAnimation animation];
    animation.keyPath = @"transform.rotation.y";
    animation.toValue = @(-M_PI_2);
    animation.duration = 2.0;
    animation.repeatDuration = INFINITY;
    animation.autoreverses = YES;
    [doorLayer addAnimation:animation forKey:nil];
}

@end

View Code

对马上间

老是研究到Core
Animation,时间都以相对的,每一个动画都有它本身描述的小时,能够独立地加速,延时依旧摇头。

beginTime点名了动画片初叶从前的的延迟时间。那里的推移从动画添加到可知图层的那一刻开端度量,私下认可是0(就是说动画会登时实施)。

speed是1个时刻的翻番,暗中认可1.0,减少它会减慢图层/动画的时日,扩张它会加快速度。要是2.0的快慢,那么对于二个duration为1的卡通片,实际上在0.5秒的时候就早已成功了。

timeOffsetbeginTime恍如,可是和扩展beginTime导致的推迟动画区别,增添timeOffset只是让动画快进到某一点,例如,对于1个频频1秒的卡通来说,设置timeOffset为0.5意味动画将从大体上的地点初步。

beginTime不等的是,timeOffset并不受speed的震慑。所以若是你把speed设为2.0,把timeOffset设置为0.5,那么您的卡通片将从动画最终完工的地点初叶,因为1秒的卡通实际上被缩小到了0.5秒。但是就是使用了timeOffset让动画片从甘休的地点起先,它如故播放了二个全体的时间长度,那几个动画仅仅是循环了一圈,然后从头开播。

能够用清单9.3的测试程序验证一下,设置speedtimeOffset滑块到任意的值,然后点击播放来考察效果(见图9.3)

清单9.3 测试timeOffsetspeed属性

 

澳门金冠网站主页 13澳门金冠网站主页 14

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 @property (nonatomic, weak) IBOutlet UILabel *speedLabel;
 5 @property (nonatomic, weak) IBOutlet UILabel *timeOffsetLabel;
 6 @property (nonatomic, weak) IBOutlet UISlider *speedSlider;
 7 @property (nonatomic, weak) IBOutlet UISlider *timeOffsetSlider;
 8 @property (nonatomic, strong) UIBezierPath *bezierPath;
 9 @property (nonatomic, strong) CALayer *shipLayer;
10 
11 @end
12 
13 @implementation ViewController
14 
15 - (void)viewDidLoad
16 {
17     [super viewDidLoad];
18     //create a path
19     self.bezierPath = [[UIBezierPath alloc] init];
20     [self.bezierPath moveToPoint:CGPointMake(0, 150)];
21     [self.bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
22     //draw the path using a CAShapeLayer
23     CAShapeLayer *pathLayer = [CAShapeLayer layer];
24     pathLayer.path = self.bezierPath.CGPath;
25     pathLayer.fillColor = [UIColor clearColor].CGColor;
26     pathLayer.strokeColor = [UIColor redColor].CGColor;
27     pathLayer.lineWidth = 3.0f;
28     [self.containerView.layer addSublayer:pathLayer];
29     //add the ship
30     self.shipLayer = [CALayer layer];
31     self.shipLayer.frame = CGRectMake(0, 0, 64, 64);
32     self.shipLayer.position = CGPointMake(0, 150);
33     self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
34     [self.containerView.layer addSublayer:self.shipLayer];
35     //set initial values
36     [self updateSliders];
37 }
38 
39 - (IBAction)updateSliders
40 {
41     CFTimeInterval timeOffset = self.timeOffsetSlider.value;
42     self.timeOffsetLabel.text = [NSString stringWithFormat:@"%0.2f", timeOffset];
43     float speed = self.speedSlider.value;
44     self.speedLabel.text = [NSString stringWithFormat:@"%0.2f", speed];
45 }
46 
47 - (IBAction)play
48 {
49     //create the keyframe animation
50     CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
51     animation.keyPath = @"position";
52     animation.timeOffset = self.timeOffsetSlider.value;
53     animation.speed = self.speedSlider.value;
54     animation.duration = 1.0;
55     animation.path = self.bezierPath.CGPath;
56     animation.rotationMode = kCAAnimationRotateAuto;
57     animation.removedOnCompletion = NO;
58     [self.shipLayer addAnimation:animation forKey:@"slide"];
59 }
60 
61 @end

View Code

澳门金冠网站主页 15

图9.3 测试时间偏移和速度的简要的应用程序

相对时间

历次探究到Core
Animation,时间都以绝对的,种种动画都有它和谐描述的时刻,能够独自地加快,延时照旧摇头。

beginTime点名了动画片初始之前的的延迟时间。那里的推移从动画添加到可知图层的那一刻初步衡量,暗中认可是0(正是说动画会立时执行)。

speed是3个时光的翻番,暗中同意1.0,缩小它会放慢图层/动画的日子,增添它会加火速度。借使2.0的快慢,那么对于二个duration为1的动画,实际上在0.5秒的时候就早已到位了。

timeOffsetbeginTime看似,可是和充实beginTime致使的推移动画不一样,增添timeOffset只是让动画片快进到某一点,例如,对于3个连发1秒的卡通片来说,设置timeOffset为0.5象征动画将从大体上的地方起先。

beginTime今非昔比的是,timeOffset并不受speed的影响。所以只要您把speed设为2.0,把timeOffset安装为0.5,那么你的动画将从动画最终竣事的地方开头,因为1秒的动画片实际上被浓缩到了0.5秒。可是即便选择了timeOffset让动画片从甘休的地点开始,它依然播放了二个完完全全的时间长度,这几个动画仅仅是循环了一圈,然后从头开始播放。

能够用清单9.3的测试程序验证一下,设置speedtimeOffset滑块到自由的值,然后点击播放来考察效果(见图9.3)

清单9.3 测试timeOffsetspeed属性

 

澳门金冠网站主页 16澳门金冠网站主页 17

 1 @interface ViewController ()
 2 
 3 @property (nonatomic, weak) IBOutlet UIView *containerView;
 4 @property (nonatomic, weak) IBOutlet UILabel *speedLabel;
 5 @property (nonatomic, weak) IBOutlet UILabel *timeOffsetLabel;
 6 @property (nonatomic, weak) IBOutlet UISlider *speedSlider;
 7 @property (nonatomic, weak) IBOutlet UISlider *timeOffsetSlider;
 8 @property (nonatomic, strong) UIBezierPath *bezierPath;
 9 @property (nonatomic, strong) CALayer *shipLayer;
10 
11 @end
12 
13 @implementation ViewController
14 
15 - (void)viewDidLoad
16 {
17     [super viewDidLoad];
18     //create a path
19     self.bezierPath = [[UIBezierPath alloc] init];
20     [self.bezierPath moveToPoint:CGPointMake(0, 150)];
21     [self.bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
22     //draw the path using a CAShapeLayer
23     CAShapeLayer *pathLayer = [CAShapeLayer layer];
24     pathLayer.path = self.bezierPath.CGPath;
25     pathLayer.fillColor = [UIColor clearColor].CGColor;
26     pathLayer.strokeColor = [UIColor redColor].CGColor;
27     pathLayer.lineWidth = 3.0f;
28     [self.containerView.layer addSublayer:pathLayer];
29     //add the ship
30     self.shipLayer = [CALayer layer];
31     self.shipLayer.frame = CGRectMake(0, 0, 64, 64);
32     self.shipLayer.position = CGPointMake(0, 150);
33     self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
34     [self.containerView.layer addSublayer:self.shipLayer];
35     //set initial values
36     [self updateSliders];
37 }
38 
39 - (IBAction)updateSliders
40 {
41     CFTimeInterval timeOffset = self.timeOffsetSlider.value;
42     self.timeOffsetLabel.text = [NSString stringWithFormat:@"%0.2f", timeOffset];
43     float speed = self.speedSlider.value;
44     self.speedLabel.text = [NSString stringWithFormat:@"%0.2f", speed];
45 }
46 
47 - (IBAction)play
48 {
49     //create the keyframe animation
50     CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
51     animation.keyPath = @"position";
52     animation.timeOffset = self.timeOffsetSlider.value;
53     animation.speed = self.speedSlider.value;
54     animation.duration = 1.0;
55     animation.path = self.bezierPath.CGPath;
56     animation.rotationMode = kCAAnimationRotateAuto;
57     animation.removedOnCompletion = NO;
58     [self.shipLayer addAnimation:animation forKey:@"slide"];
59 }
60 
61 @end

View Code

澳门金冠网站主页 18

图9.3 测试时间偏移和进程的简练的应用程序

fillMode

对于beginTime非0的一段动画来说,晤面世四个当动画添加到图层上但哪些也没爆发的状态。类似的,removeOnCompletion棉被服装置为NO的卡通将会在动画甘休的时候依然保持以前的情况。那就生出了3个标题,当动画初叶在此之前和动画片停止之后,被安装动画的性质将会是何许值吗?

一种恐怕是性质和动画没被添加从前保持一致,也便是在模型图层定义的值(见第⑧章“隐式动画”,模型图层和突显图层的诠释)。

另一种恐怕是维持动画伊始在此以前那一帧,或许动画片截至之后的那一帧。那就是所谓的填充,因为动画开始和得了的值用来填充开首此前和结束以往的时日。

那种行为就付出开发者了,它能够被CAMediaTimingfillMode来控制。fillMode是一个NSString花色,还可以如下八种常量:

kCAFillModeForwards 
kCAFillModeBackwards 
kCAFillModeBoth 
kCAFillModeRemoved

默认是kCAFillModeRemoved,当动画不再播放的时候就展现图层模型钦命的值剩下的三系列型向前,向后可能即上前又向后去填充动画状态,使得动画在起来前只怕终止后依然保持开端和告竣那一刻的值。

这就对幸免在动画甘休的时候急忙重临提供另一种方案(见第玖章)。不过切记了,当用它来消除这几个题指标时候,需求把removeOnCompletion设置为NO,其它须求给动画添加二个非空的键,于是能够在不要求动画的时候把它从图层上移除。

 

 

fillMode

对于beginTime非0的一段动画来说,会油但是生2个当动画添加到图层上但哪些也没发出的情形。类似的,removeOnCompletion被设置为NO的卡通片将会在动画甘休的时候依然维持从前的情况。那就发出了三个难点,当动画开首在此以前和卡通甘休以往,被安装动画的品质将会是怎么值吗?

一种恐怕是性质和动画片没被增加在此之前保持一致,也正是在模型图层定义的值(见第⑧章“隐式动画”,模型图层和展现图层的表达)。

另一种恐怕是涵养动画开首从前那一帧,或许动画片截止之后的那一帧。那正是所谓的澳门金冠网站主页,填充,因为动画伊始和了结的值用来填充早先在此之前和完工之后的岁月。

那种行为就提交开发者了,它能够被CAMediaTimingfillMode来控制。fillMode是一个NSString项目,能够承受如下八种常量:

kCAFillModeForwards 
kCAFillModeBackwards 
kCAFillModeBoth 
kCAFillModeRemoved

默认是kCAFillModeRemoved,当动画不再播放的时候就呈现图层模型内定的值剩下的三连串型向前,向后要么即上前又向后去填充动画状态,使得动画在起来前或许终止后仍然维持起头和终止那一刻的值。

那就对制止在动画结束的时候快速重回提供另一种方案(见第楚辞)。可是切记了,当用它来解决那些题材的时候,要求把removeOnCompletion设置为NO,其它索要给动画添加一个非空的键,于是能够在不需求动画的时候把它从图层上移除。

 

 

相关文章