CABasicAnimation

本文深入探讨了Core Animation中的CAPropertyAnimation、CABasicAnimation与CAKeyFrameAnimation等关键技术,展示了如何通过这些API实现图形层的动画效果。文章提供了实例代码,包括属性动画的创建、配置与应用,以及动画的控制与监测方法。此外,还介绍了几个用于实现热门APP应用中menu效果的动画方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >




CAAnimation---CAPropertyAnimation---CABasicAnimation & CAKeyFrameAnimation

CAPropertyAnimation:作用于图层的某个单一属性,并指定它的一个目标值,或者一连串将要做动画的值。CAPropertyAnimation通过指定动画的keyPath作用于单一的属性,CAAnimation通常应用于一个指定的CALayer,于是这里的keyPath指的也就是图层的keyPath了。实际这个keyPath是一个关键路径,而不仅仅是一个属性的名称。这意味着动画不仅可以作用于图层本身的属性,还包含了它的子成员的属性,甚至是一些虚拟的属性。

CABasicAnimation 继承于CAPropertyAnimation,并添加了三个属性: fromValue、toValue、byValue[注:三个属性都是id类型,因为属性动画可以用作很多不同种的属性类型,包括数字类型、矢量、变换矩阵、甚至是颜色或者图片]

一般我们只需要使用三个属性中的两个fromValue & toValue或者fromValue & byValue。

eg:如果设置了fromValue = 2, toValue = 5,byValue = 6。那么Core Animation就不知道结果到底是2->5,还是2->(2 + 6)。两种用法会冲突。

当你创建一个 CABasicAnimation 时,你需要通过-setFromValue 和-setToValue 来指定一个开始值和结束值。 当你增加基础动画到层中的时候,它开始运行。当用属性做动画完成时,例如用位置属性做动画,层就会立刻返回到它的初始位置。因为动画并没有改变图层的模型,而只是呈现,并没有真的改变属性的值。如果你想改变属性的值,必须显式的设置该属性的值。 [在有些时候,比如你想改变层的背景色,这时候你真的改变属性的值(在动画开始之前或者结束后),效果也许会好点]

CAAnimationDelegate扩展NSObject类的两个方法可以监测动画的开始和结束:

- (void)animationDidStart:(CAAnimation *)aim;

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag; 

UIView *view0 = [[UIView alloc]initWithFrame:CGRectMake(100, 0, 100, 100)];
    [self.view addSubview:view0];
    CABasicAnimation *contents = [CABasicAnimation animationWithKeyPath:@"contents"];
    contents.duration = 1.f;
    contents.fromValue = (id)[UIImage imageNamed:@"星空"].CGImage;
    contents.toValue = (id)[UIImage imageNamed:@"艾薇儿"].CGImage;
    contents.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    contents.repeatCount = CGFLOAT_MAX;
    contents.autoreverses = YES;
    [view0.layer addAnimation:contents forKey:@"contents"];//<span style="font-family: verdana, Arial, Helvetica, sans-serif;">这告诉了层当需要做动画时, 使用我们给关键路径指定的新动画。</span>
如果我们没有设置最后一句的key,那么将找不到我们设置的animation,会使用默认的动画。

下面是一些继承的常用的属性

Autoreverses  : 当你设定这个属性为 YES 时,在它到达目的地之后,动画的返回到开始的值,代替了直接跳转到开始的值。 

Duration: Duration 这个参数你已经相当熟悉了。它设定开始值到结束值花费的时间。期间会被速度的属性所影响。 

RemovedOnCompletion : 这个属性默认为 YES,那意味着,在指定的时间段完成后,动画就自动的从层上移除了。这个一般不用。

假如你想要再次用这个动画时,你需要设定这个属性为 NO。这样的话,下次你在通过-set 方法设定动画的属 性时,它将再次使用你的动画,而非默认的动画。

Speed : 默认的值为 1.0.这意味着动画播放按照默认的速度。如果你改变这个值为 2.0,动画会用 倍的速度播放。 这样的影响就是使持续时间减半。如果你指定的持续时间为 秒,速度为 2.0,动画就会播放 秒钟---一半的 持续时间。

BeginTime : 这个属性在组动画中很有用。它根据父动画组的持续时间,指定了开始播放动画的时间。默认的是 0.0

TimeOffset : 如果一个时间偏移量是被设定,动画不会真正的可见,直到根据父动画组中的执行时间得到的时间都流逝 了。

RepeatCount : 默认的是 0,意味着动画只会播放一次。如果指定一个无限大的重复次数,使用 1e100f。这个不应该和 repeatDration 属性一块使用。

RepeatDuration : 这个属性指定了动画应该被重复多久。动画会一直重复,直到设定的时间流逝完。它不应该和 repeatCount 一起使用。 

通常这样联合使用来让动画停在最后的位置,但是属性的值没改,除非手动更改。

animationTranslation.removedOnCompletion =NO;

animationTranslation.fillMode =kCAFillModeForwards;


animationWithKeyPath的值

  transform.scale = 比例轉換

    transform.scale.x = 闊的比例轉換

    transform.scale.y = 高的比例轉換

    transform.rotation.z = 平面圖的旋轉

    opacity = 透明度

    margin

    zPosition

    backgroundColor    背景颜色

    cornerRadius    圆角

    borderWidth

    bounds

    contents

    contentsRect

    cornerRadius

    frame

    hidden

    mask

    masksToBounds

    opacity

    position

    shadowColor

    shadowOffset

    shadowOpacity

    shadowRadius

 

下面是一些例子

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    CABasicAnimation *pulse = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    pulse.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    pulse.duration = 0.5 + (rand() % 10) * 0.05;
    pulse.repeatCount = 1;
    pulse.autoreverses = YES;
    pulse.fromValue = [NSNumber numberWithFloat:.8];
    pulse.toValue = [NSNumber numberWithFloat:1.2];
    [self.ui_View.layer addAnimation:pulse forKey:nil];
 
// bounds
  
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"bounds"];
    anim.duration = 1.f;
    anim.fromValue = [NSValue valueWithCGRect:CGRectMake(0,0,10,10)];
    anim.toValue = [NSValue valueWithCGRect:CGRectMake(10,10,200,200)];
    anim.byValue  = [NSValue valueWithCGRect:self. ui_View.bounds]; 
//    anim.toValue = (id)[UIColor redColor].CGColor;
//    anim.fromValue =  (id)[UIColor blackColor].CGColor;
     
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.repeatCount = 1;
    anim.autoreverses = YES;
     
    [ui_View.layer addAnimation:anim forKey:nil];
//cornerRadius
  
    CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
    anim2.duration = 1.f;
    anim2.fromValue = [NSNumber numberWithFloat:0.f];
    anim2.toValue = [NSNumber numberWithFloat:20.f];
    anim2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim2.repeatCount = CGFLOAT_MAX;
    anim2.autoreverses = YES;
     
    [ui_View.layer addAnimation:anim2 forKey:@"cornerRadius"];
 
//contents
  
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"contents"];
    anim.duration = 1.f;
    anim.fromValue = (id)[UIImage imageNamed:@"1.jpg"].CGImage;
    anim.toValue = (id)[UIImage imageNamed:@"2.png"].CGImage;
//    anim.byValue  = (id)[UIImage imageNamed:@"3.png"].CGImage;
//    anim.toValue = (id)[UIColor redColor].CGColor;
//    anim.fromValue =  (id)[UIColor blackColor].CGColor;
     
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.repeatCount = CGFLOAT_MAX;
    anim.autoreverses = YES;
     
    [ui_View.layer addAnimation:anim forKey:nil];
 
 
  
[ui_View.layer setShadowOffset:CGSizeMake(2,2)];
    [ui_View.layer setShadowOpacity:1];
    [ui_View.layer setShadowColor:[UIColor grayColor].CGColor];
//
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"shadowColor"];
    anim.duration = 1.f;
    anim.toValue = (id)[UIColor redColor].CGColor;
    anim.fromValue =  (id)[UIColor blackColor].CGColor;
     
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.repeatCount = CGFLOAT_MAX;
    anim.autoreverses = YES;
     
    [ui_View.layer addAnimation:anim forKey:nil];
     
    CABasicAnimation *_anim = [CABasicAnimation animationWithKeyPath:@"shadowOffset"];
    _anim.duration = 1.f;
    _anim.fromValue = [NSValue valueWithCGSize:CGSizeMake(0,0)];
    _anim.toValue = [NSValue valueWithCGSize:CGSizeMake(3,3)];
     
    _anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    _anim.repeatCount = CGFLOAT_MAX;
    _anim.autoreverses = YES;
     
    [ui_View.layer addAnimation:_anim forKey:nil];
     
     
    CABasicAnimation *_anim1 = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
    _anim1.duration = 1.f;
    _anim1.fromValue = [NSNumber numberWithFloat:0.5];
    _anim1.toValue = [NSNumber numberWithFloat:1];
     
    _anim1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    _anim1.repeatCount = CGFLOAT_MAX;
    _anim1.autoreverses = YES;
     
    [ui_View.layer addAnimation:_anim1 forKey:nil];
     
     
     
    CABasicAnimation *_anim2 = [CABasicAnimation animationWithKeyPath:@"shadowRadius"];
    _anim2.duration = 1.f;
    _anim2.fromValue = [NSNumber numberWithFloat:10];
    _anim2.toValue = [NSNumber numberWithFloat:5];
     
    _anim2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    _anim2.repeatCount = CGFLOAT_MAX;
    _anim2.autoreverses = YES;
     
    [ui_View.layer addAnimation:_anim2 forKey:nil];

 下面是一些应用

 

几个可以用来实现热门APP应用PATH中menu效果的几个方法
 
+(CABasicAnimation *)opacityForever_Animation:(float)time //永久闪烁的动画
 
{
 
    CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"opacity"];
 
    animation.fromValue=[NSNumber numberWithFloat:1.0];
 
    animation.toValue=[NSNumber numberWithFloat:0.0];
 
    animation.autoreverses=YES;
 
    animation.duration=time;
 
    animation.repeatCount=FLT_MAX;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    return animation;
 
}
 
  
 
+(CABasicAnimation *)opacityTimes_Animation:(float)repeatTimes durTimes:(float)time; //有闪烁次数的动画
 
{
 
    CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"opacity"];
 
    animation.fromValue=[NSNumber numberWithFloat:1.0];
 
    animation.toValue=[NSNumber numberWithFloat:0.4];
 
    animation.repeatCount=repeatTimes;
 
    animation.duration=time;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
 
    animation.autoreverses=YES;
 
    return  animation;
 
}
 
  
 
+(CABasicAnimation *)moveX:(float)time X:(NSNumber *)x //横向移动
 
{
 
    CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
 
    animation.toValue=x;
 
    animation.duration=time;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    return animation;
 
}
 
  
 
+(CABasicAnimation *)moveY:(float)time Y:(NSNumber *)y //纵向移动
 
{
 
    CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
 
    animation.toValue=y;
 
    animation.duration=time;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    return animation;
 
}
 
  
 
+(CABasicAnimation *)scale:(NSNumber *)Multiple orgin:(NSNumber *)orginMultiple durTimes:(float)time Rep:(float)repeatTimes //缩放
 
{
 
    CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
 
    animation.fromValue=orginMultiple;
 
    animation.toValue=Multiple;
 
    animation.duration=time;
 
    animation.autoreverses=YES;
 
    animation.repeatCount=repeatTimes;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    return animation;
 
}
 
  
 
+(CAAnimationGroup *)groupAnimation:(NSArray *)animationAry durTimes:(float)time Rep:(float)repeatTimes //组合动画
 
{
 
    CAAnimationGroup *animation=[CAAnimationGroup animation];
 
    animation.animations=animationAry;
 
    animation.duration=time;
 
    animation.repeatCount=repeatTimes;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    return animation;
 
}
 
  
 
+(CAKeyframeAnimation *)keyframeAniamtion:(CGMutablePathRef)path durTimes:(float)time Rep:(float)repeatTimes //路径动画
 
{
 
    CAKeyframeAnimation *animation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
 
    animation.path=path;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
 
    animation.autoreverses=NO;
 
    animation.duration=time;
 
    animation.repeatCount=repeatTimes;
 
    return animation;
 
}
 
  
 
+(CABasicAnimation *)movepoint:(CGPoint )point //点移动
 
{
 
    CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.translation"];
 
    animation.toValue=[NSValue valueWithCGPoint:point];
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    return animation;
 
}
 
  
 
+(CABasicAnimation *)rotation:(float)dur degree:(float)degree direction:(int)direction repeatCount:(int)repeatCount //旋转
 
{
 
    CATransform3D rotationTransform  = CATransform3DMakeRotation(degree, 0, 0,direction);
 
    CABasicAnimation* animation;
 
    animation = [CABasicAnimation animationWithKeyPath:@"transform"];
 
  
 
animation.toValue= [NSValue valueWithCATransform3D:rotationTransform];
 
    animation.duration= dur;
 
animation.autoreverses= NO;
 
    animation.cumulative= YES;
 
    animation.removedOnCompletion=NO;
 
    animation.fillMode=kCAFillModeForwards;
 
    animation.repeatCount= repeatCount;
 
animation.delegate= self;
 
  
 
return animation;
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值