CABasicAnimation使用总结

CABasicAnimation使用总结

实例化

使用方法animationWithKeyPath:对 CABasicAnimation进行实例化,并指定Layer的属性做为关键路径进行注册。缓存

//围绕y轴旋转
CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];

设定动画

设定动画的属性和说明动画

属性 说明
duration 动画的时长
repeatCount 重复的次数。不停重复设置为 HUGE_VALF
repeatDuration 设置动画的时间。在该时间内动画一直执行,不计次数。
beginTime 指定动画开始的时间。从开始延迟几秒的话,设置为【CACurrentMediaTime() + 秒数】 的方式
timingFunction 设置动画的速度变化
autoreverses 动画结束时是否执行逆动画
fromValue 所改变属性的起始值
toValue 所改变属性的结束时的值
byValue 所改变属性相同起始值的改变量
transformAnima.fromValue = @(M_PI_2);
transformAnima.toValue = @(M_PI);
transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transformAnima.autoreverses = YES;
transformAnima.repeatCount = HUGE_VALF;
transformAnima.beginTime = CACurrentMediaTime() + 2;

防止动画结束后回到初始状态

只需设置removedOnCompletionfillMode两个属性就能够了。3d

transformAnima.removedOnCompletion = NO;
transformAnima.fillMode = kCAFillModeForwards;

解释:为何动画结束后返回原状态?
首先咱们须要搞明白一点的是,layer动画运行的过程是怎样的?其实在咱们给一个视图添加layer动画时,真正移动并非咱们的视图自己,而是 presentation layer 的一个缓存。动画开始时 presentation layer开始移动,原始layer隐藏,动画结束时,presentation layer从屏幕上移除,原始layer显示。这就解释了为何咱们的视图在动画结束后又回到了原来的状态,由于它根本就没动过。代理

这个一样也能够解释为何在动画移动过程当中,咱们为什么不能对其进行任何操做。code

因此在咱们完成layer动画以后,最好将咱们的layer属性设置为咱们最终状态的属性,而后将presentation layer 移除掉。orm

添加动画

[self.imageView.layer addAnimation:transformAnima forKey:@"A"];

须要注意的两点对象

  • 一个 CABasicAniamtion 的实例对象只是一个数据模型,和他绑定到哪个layer上是没有关系的
  • 方法addAnimation:forKey:是将 CABasicAniamtion 对象进行了 copy 操做的。因此在将其添加到一个layer上以后,咱们仍是将其再次添加到另外一个layer上的。

fillMode属性的理解

该属性定义了你的动画在开始和结束时的动做。默认值是 kCAFillModeRemovedblog

取值的解释事件

  • kCAFillModeRemoved 设置为该值,动画将在设置的 beginTime 开始执行(如没有设置beginTime属性,则动画当即执行),动画执行完成后将会layer的改变恢复原状。
 
 
  • kCAFillModeForwards 设置为该值,动画即便以后layer的状态将保持在动画的最后一帧,而removedOnCompletion的默认属性值是 YES,因此为了使动画结束以后layer保持结束状态,应将removedOnCompletion设置为NO。
 
 
  • kCAFillModeBackwards 设置为该值,将会当即执行动画的第一帧,不管是否设置了 beginTime属性。观察发现,设置该值,刚开始视图不见,还不知道应用在哪里。
 
 
  • kCAFillModeBoth 该值是 kCAFillModeForwards 和 kCAFillModeBackwards的组合状态
 
 

Animation Easing的使用

也便是属性timingFunction值的设定,有种方式来获取属性值图片

(1)使用方法functionWithName:

这种方式很简单,这里只是简单说明一下取值的含义:

  • kCAMediaTimingFunctionLinear 传这个值,在整个动画时间内动画都是以一个相同的速度来改变。也就是匀速运动。

  • kCAMediaTimingFunctionEaseIn 使用该值,动画开始时会较慢,以后动画会加速。


     
     
  • kCAMediaTimingFunctionEaseOut 使用该值,动画在开始时会较快,以后动画速度减慢。


     
     
  • kCAMediaTimingFunctionEaseInEaseOut 使用该值,动画在开始和结束时速度较慢,中间时间段内速度较快。


     
     
(2)使用方法functionWithControlPoints: : : :实现,这个以后再说,占个坑先。

其余的一些设置属性

  • repeatCount 设置动画的执行次数
  • autoreverses 默认值为 NO,将其设置为 YES
  • speed 改变更画的速度 能够直接设置动画上的speed属性,这样只有这个动画速度。
    animation.speed = 2;
    或者在layer上设置speed属性,这样在该视图上的全部动画都提速,该视图上的全部子视图上的动画也会提速。
    speed两点需注意的:
    (1) 若是设置动画时间为4s,speed设置为2,则动画只需2s便可执行完。
    (2)若是同时设置了动画的speed和layer 的speed,则实际的speed为二者相乘。

使用总结

  • 在动画执行完成以后,最好仍是将动画移除掉。也就是尽可能不要设置removedOnCompletion属性为NO
  • fillMode尽可能取默认值就行了,不要去设置它的值。只有在极个别的状况下咱们会修改它的值,之后会说到,这里先占个坑。
  • 解决有时视图会闪动一下的问题,咱们能够将layer的属性值设置为咱们的动画最后要达到的值,而后再给咱们的视图添加layer动画。

例子(移动动画实现)

直接上代码

CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.duration = 0.8;
positionAnima.fromValue = @(self.imageView.center.y);
positionAnima.toValue = @(self.imageView.center.y-30);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
positionAnima.repeatCount = HUGE_VALF;
positionAnima.repeatDuration = 2;
positionAnima.removedOnCompletion = NO;
positionAnima.fillMode = kCAFillModeForwards;

[self.imageView.layer addAnimation:positionAnima forKey:@"AnimationMoveY"];

组合动画的实现

CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.fromValue = @(self.imageView.center.y);
positionAnima.toValue = @(self.imageView.center.y-30);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];


CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
transformAnima.fromValue = @(0);
transformAnima.toValue = @(M_PI);
transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

CAAnimationGroup *animaGroup = [CAAnimationGroup animation];
animaGroup.duration = 2.0f;
animaGroup.fillMode = kCAFillModeForwards;
animaGroup.removedOnCompletion = NO;
animaGroup.animations = @[positionAnima,transformAnima];

[self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];

动画开始和结束时的事件

为了获取动画的开始和结束事件,须要实现协议

positionAnima.delegate = self;

代理方法实现

//动画开始时
- (void)animationDidStart:(CAAnimation *)anim
{
    NSLog(@"开始了");
}

//动画结束时
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    //方法中的flag参数代表了动画是天然结束仍是被打断,好比调用了removeAnimationForKey:方法或removeAnimationForKey方法,flag为NO,若是是正常结束,flag为YES。
    NSLog(@"结束了");
}

其实比较重要的是有多个动画的时候如何在代理方法中区分不一样的动画
两种方式

方式一:

若是咱们添加动画的视图是全局变量,可以使用该方法。
添加动画时,咱们使用了

[self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];

因此,可根据key来区分不一样的动画

//动画开始时
- (void)animationDidStart:(CAAnimation *)anim
{
    if ([anim isEqual:[self.imageView.layer animationForKey:@"Animation"]]) {
        NSLog(@"动画组执行了");
    }
}

Note:把动画存储为一个属性而后再回调中比较,用来断定是哪一个动画是不可行的。应为委托传入的动画参数是原始值的一个深拷贝,不是同一个值

方式二

添加动画的视图是局部变量时,可以使用该方法
添加动画给动画设置key-value对

[positionAnima setValue:@"PositionAnima" forKey:@"AnimationKey"];

[transformAnima setValue:@"TransformAnima" forKey:@"AnimationKey"];

因此,能够根据key中不一样的值来进行区分不一样的动画

//动画结束时
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"PositionAnima"]) {
        NSLog(@"位置移动动画执行结束");
    }
    else if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"TransformAnima"]){
        NSLog(@"旋转动画执行结束");
    }
}

解决循环引用问题

因为CAAnimation的delegate使用的strong类型,

 
 

因此在全局变量以下设置时会产生循环引用的状况

self.animation.delegate = self;//可经过复用dealloc方法来验证

解决方案

  • 声明一个单独的类实现delegate的回调
//.h
#import <UIKit/UIKit.h>

@interface AnimationDelegate : NSObject

@end

//.m
#import "AnimationDelegate.h"

@implementation AnimationDelegate

- (void)animationDidStart:(CAAnimation *)anim
{
    NSLog(@"Animation Start");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    NSLog(@"Animation Stop");
}

- (void)dealloc
{
    NSLog(@"Delegate Dealloc");
}

@end

使用方式

self.animation.delegate = [[AnimationDelegate alloc]init];
  • 使用NSProxy来解决
    该类可直接引用YYKit中的YYWeakProxy
    使用方法
self.animation.delegate = [YYWeakProxy proxyWithTarget:self];

一些经常使用的animationWithKeyPath值的总结

说明 使用形式
transform.scale 比例转化 @(0.8)
transform.scale.x 宽的比例 @(0.8)
transform.scale.y 高的比例 @(0.8)
transform.rotation.x 围绕x轴旋转 @(M_PI)
transform.rotation.y 围绕y轴旋转 @(M_PI)
transform.rotation.z 围绕z轴旋转 @(M_PI)
cornerRadius 圆角的设置 @(50)
backgroundColor 背景颜色的变化 (id)[UIColor purpleColor].CGColor
bounds 大小,中心不变 [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)];
position 位置(中心点的改变) [NSValue valueWithCGPoint:CGPointMake(300, 300)];
contents 内容,好比UIImageView的图片 imageAnima.toValue = (id)[UIImage imageNamed:@"to"].CGImage;
opacity 透明度 @(0.7)
contentsRect.size.width 横向拉伸缩放 @(0.4)最好是0~1之间的
相关文章
相关标签/搜索