美文网首页
CoreAnimation使用笔记

CoreAnimation使用笔记

作者: 栋柠柒 | 来源:发表于2018-08-11 23:43 被阅读98次

    核心动画(CoreAnimation)的类图


    1498114752750475.png

    分析一下图上的结构:

    1.CAMediaTiming 协议中定义了时间,速度,重复次数等。属性定义如下:
    beginTime -> 用来设置动画延时,若想延迟1秒,就设置为CACurrentMediaTime()+1,其中CACurrentMediaTime()为图层当前时间。
    duration -> 动画的持续时间。
    speed -> 动画速率,决定动画时间的倍率。当speed为2时,动画时间为设置的duration的1/2。
    timeOffset -> 动画时间偏移量。比如设置动画时长为3秒,当设置timeOffset为1.5时,当前动画会从中间位置开始,并在到达指定位置时,走完之前跳过的前半段动画。
    repeatCount -> 动画的重复次数。
    repeatDuration -> 动画的重复时间。
    autoreverses -> 动画由初始值到最终值后,是否反过来回到初始值的动画。如果设置为YES,就意味着动画完成后会以动画的形式回到初始值。
    fillMode -> 决定当前对象在非动画时间段的行为.比如动画开始之前,动画结束之后。
    ??:其实不只是CAAnimation遵循CAMediaTiming协议,熟悉底层结构的小伙伴们应该知道CALayer也遵循这个协议,所有在一定程度上我们可以通过控制layer本身的协议属性来控制动画节奏。

    2.CAAnimation 核心动画基础类,不能直接使用。除了CAMediaTiming协议中的方法,增加了CAAnimationDelegate的代理属性等。具体如下:
    timingFunction -> 控制动画的节奏。系统提供的包括:kCAMediaTimingFunctionLinear (匀速),kCAMediaTimingFunctionEaseIn (慢进快出),kCAMediaTimingFunctionEaseOut (快进慢出),kCAMediaTimingFunctionEaseInEaseOut (慢进慢出,中间加速),kCAMediaTimingFunctionDefault (默认),当然也可通过自定义创建CAMediaTimingFunction。
    delegate -> 代理。
    removedOnCompletion -> 是否让图层保持显示动画执行后的状态,默认为YES,也就是动画执行完毕后从涂层上移除,恢复到执行前的状态,如果设置为NO,并且设置fillMode为kCAFillModeForwards,则保持动画执行后的状态。

    3.CAPropertyAnimation 属性动画,针对对象的可动画属性进行效果的设置,不可直接使用。添加属性具体如下:
    keyPath -> CALayer的某个属性名,并通过这个属性的值进行修改,达到相应的动画效果。
    additive -> 属性动画是否以当前动画效果为基础,默认为NO。
    cumulative -> 指定动画是否为累加效果,默认为NO。
    valueFunction -> 此属性配合CALayer的transform属性使用。

    4.CABasicAnimation基础动画,通过keyPath对应属性进行控制,需要设置fromValue以及toValue。添加属性如下:
    fromValue -> keyPath相应属性的初始值。
    toValue -> keyPath相应属性的结束值。
    byValue -> 在不设置toValue时,toValue = fromValue + byValue,也就是在当前的位置上增加多少。

    5.CASpringAnimation 带有初始速度以及阻尼指数等物理参数的属性动画。我们可以把它看成在不绝对光滑的地面上,一个弹簧拴着别小球,那么我们可以这么理解他的属性(物理知识请问一下牛顿大叔):
    mass -> 小球质量,影响惯性。
    stiffness -> 弹簧的劲度系数。
    damping -> 阻尼系数,地面的摩擦力。
    initialVelocity -> 初始速度,相当于给小球一个初始速度(可正可负,方向不同)
    settlingDuration -> 结算时间,根据上述参数计算出的预计时间,相对于你设置的时间,这个时间比较准确。

    6.CAKeyframeAnimation 关键帧动画,同样通过keyPath对应属性进行控制,但它可以通过values或者path进行多个阶段的控制。属性如下:
    values -> 关键帧组成的数组,动画会依次显示其中的每一帧。
    path -> 关键帧路径,动画进行的要素,优先级比values高,但是只对CALayer的anchorPoint和position起作用。
    keyTimes -> 每一帧对应的时间,如果不设置,则各关键帧平分设定时间。
    timingFunctions -> 每一帧对应的动画节奏。
    calculationMode -> 动画的计算模式,系统提供了对应的几种模式。
    tensionValues -> 动画张力控制。
    continuityValues -> 动画连续性控制。
    biasValues -> 动画偏差率控制。
    rotationMode -> 动画沿路径旋转方式,系统提供了两种模式。

    7.CATransition 转场动画,系统提供了很多酷炫效果。属性如下:
    type -> 转场动画类型。
    subtype -> 转场动画方向。
    startProgress -> 动画起点进度(整体的百分比)。
    endProgress -> 动画终点进度(整体的百分比)。
    filter -> 自定义转场。

    8.CAAnimationGroup 动画组,方便对于多动画的统一控制管理。
    animations -> 所有动画效果元素的数组。

    CABasicAnimation
    在一般的应用开发中,基础动画可以满足大部分的开发需求,主要完成对于对象指定动画属性两个Value之间的动画过度。

    具体过程如下:
    1.初始化动画并设置动画keyPath(keyPath为指定动画效果的CALayer的某个属性名,比如position属性)
    2.设置动画其他属性,比如delegate,fromValue,toValue,duration等
    3.利用- (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;添加给指定layer添加动画
    4.利用- (void)removeAllAnimations;或-(void)removeAnimationForKey:(NSString *)key;方法停止所有或者指定动画

    我们下面写一个简单的位移动画:
    首先,创建一个做动画的layer:

    self.aniLayer = [[CALayer alloc] init];
     _aniLayer.bounds = CGRectMake(0, 0, 100, 100);
     _aniLayer.position = self.view.center;
    _aniLayer.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:_aniLayer];
    生成一个CADisplayLink,我们来看一下我们上面说过的layer的层级结构:
    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
    _displayLink.frameInterval = 30;
    [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    //
    -(void)handleDisplayLink:(CADisplayLink *)displayLink{
        NSLog(@"modelLayer_%@,presentLayer_%@",[NSValue valueWithCGPoint:_aniLayer.position],[NSValue valueWithCGPoint:_aniLayer.presentationLayer.position]);
    }
    在点击屏幕时,触发动画:
    -(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event{
        CGPoint positon = [touches.anyObject locationInView:self.view];
        [self basicAnimation_PositionTo:positon];
    }
    动画:
    -(void)basicAnimation_PositionTo:(CGPoint)position{
        //初始化动画并设置keyPath
        CABasicAnimation *basicAni = [CABasicAnimation animationWithKeyPath:@"position"];
        //设置代理
        basicAni.delegate = self;
        //到达位置
        basicAni.toValue = [NSValue valueWithCGPoint:position];
        //延时执行
        //basicAni.beginTime = CACurrentMediaTime() + 2;
        //动画时间
        basicAni.duration = 3;
        //动画节奏
        basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        //动画速率
        //basicAni.speed = 0.1;
        //图层是否显示执行后的动画执行后的位置以及状态
        basicAni.removedOnCompletion = NO;
        basicAni.fillMode = kCAFillModeForwards;
        //动画完成后是否以动画形式回到初始值
        //basicAni.autoreverses = YES;
        //动画时间偏移
        //basicAni.timeOffset = 0.5;
        //添加动画
        [_aniLayer addAnimation:basicAni forKey:NSStringFromSelector(_cmd)];
    }
    
    运行效果: image

    打印结果:

    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {187.5, 333.5}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {182.1122316699475, 343.44501110725105}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {161.77888754755259, 380.97731033712626}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {128.82425409555435, 441.80661398172379}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {94.108665972948074, 505.88637545704842}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {70.035845696926117, 550.32118600606918}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {61.103064090013504, 566.80975916981697}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {61, 567}
    CoreAnimaitonPlayground[3669:389016] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {61, 567}
    
    

    下面我们做一个修改:
    在实现动画时,我们注释掉这两行:

    //basicAni.removedOnCompletion = NO;
    //basicAni.fillMode = kCAFillModeForwards;
    

    运行结果:


    image

    打印结果:

    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {187.5, 333.5}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {187.33332352247089, 333.85210405878024}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {178.31957995891571, 352.89363733679056}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {155.03444194793701, 402.08349138498306}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {121.92566871643066, 472.02577483654022}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {90.934395790100098, 537.49483889341354}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {72.198107242584229, 577.07524845004082}
    CoreAnimaitonPlayground[3710:397153] modelLayer_NSPoint: {187.5, 333.5},presentLayer_NSPoint: {187.5, 333.5}
    

    去掉这两行代码后,layer完成动画后跳回到开始的位置,我们看到的这种现象结合layer层级的打印,我们可以确定:动画本身并没有改变model tree的位置,我们看到的动画是presentation tree运动的轨迹。当设置removedOnCompletion 属性为NO以及fillMode属性为kCAFillModeForwards时,也并未改变model tree的位置,但是可以使动画结束后,防止presentation tree被移除并回到动画开始的位置。所以并不建议使用removedOnCompletion配合fillMode的方式来实现动画结束时,图层不跳转回原位的实现,我们应该在动画开始或者结束时重新设置它的位置。我们这么做:

    //储存结束位置
    [basicAni setValue:[NSValue valueWithCGPoint: position] forKey:@"positionToEnd"];
    //动画结束后,重新设置它的位置
    -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
        _aniLayer.position = [[anim valueForKey:@"positionToEnd"] CGPointValue];
    }
    

    我们来看一下效果:


    image

    我们发现了另一个问题,当动画完成后,它会重新从起点运动到终点,一看就是上一节课没认真听,这就是因为我们之前提到的,对于非根图层,设置它的可动画属性是有隐式动画的,那么我们需要关闭图层的隐式动画,我们就需要用到动画事务CATransaction:

    说到这,我们就简单介绍一下CATransaction,有人说,我好像没见过这个东西,他是个什么鬼?和NSAutoreleasePool一样,当我们不手动创建时,系统会在一帧开始时生成一个事务,并在这一帧结束时commit,这也就是隐式CATransaction。当然你也可以利用[CATransaction begin]方法开始,调用[CATransaction commit]方法结束,中间便是事务的作用域,然后把需要更改可动画属性的操作放在该作用域内,这就是显式CATransaction,它常常用于关闭隐式动画和调整动画时间。下面我们就用它来关闭修改图层的position时所带来的隐式动画:

    动画结束时我们这样写:

    -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
        //开始事务
        [CATransaction begin];
        //关闭隐式动画
        [CATransaction setDisableActions:YES];
        _aniLayer.position = [[anim valueForKey:@"positionToEnd"] CGPointValue];
        //提交事务
        [CATransaction commit];
    }
    

    运行效果:


    image

    我们可以看到,这样就解决了隐式动画导致的问题啦。

    下面我们利用CABasicAnimation实现几种动画效果:

    #import "ViewController.h"
     
    #define buttonName @[@"位移",@"缩放",@"透明度",@"旋转",@"圆角"]
     
    @interface ViewController ()
    @property(nonatomic,strong)CALayer *aniLayer;
    //
    @property(nonatomic,strong)CADisplayLink *displayLink;
    @end
     
    @implementation ViewController
     
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        self.aniLayer = [[CALayer alloc] init];
        _aniLayer.bounds = CGRectMake(0, 0, 100, 100);
        _aniLayer.position = self.view.center;
        _aniLayer.backgroundColor = [UIColor redColor].CGColor;
        [self.view.layer addSublayer:_aniLayer];
        //
        for (int i = 0; i < 5; i++) {
            UIButton *aniButton = [UIButton buttonWithType:UIButtonTypeCustom];
            aniButton.tag = i;
            [aniButton setTitle:buttonName[i] forState:UIControlStateNormal];
            aniButton.exclusiveTouch = YES;
            aniButton.frame = CGRectMake(10, 50 + 60 * i, 100, 50);
            aniButton.backgroundColor = [UIColor blueColor];
            [aniButton addTarget:self action:@selector(tapAction:) forControlEvents:UIControlEventTouchUpInside];
            [self.view addSubview:aniButton];
        }
        //
    //    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
    //    _displayLink.frameInterval = 30;
    //    [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    -(void)tapAction:(UIButton*)button{
        [self basicAnimationWithTag:button.tag];
    }
     
    -(void)handleDisplayLink:(CADisplayLink *)displayLink{
        NSLog(@"modelLayer_%@,presentLayer_%@",[NSValue valueWithCGPoint:_aniLayer.position],[NSValue valueWithCGPoint:_aniLayer.presentationLayer.position]);
    }
     
    -(void)basicAnimationWithTag:(NSInteger)tag{
        CABasicAnimation *basicAni = nil;
        switch (tag) {
            case 0:
                //初始化动画并设置keyPath
                basicAni = [CABasicAnimation animationWithKeyPath:@"position"];
                //到达位置
                basicAni.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
                break;
            case 1:
                //初始化动画并设置keyPath
                basicAni = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
                //到达缩放
                basicAni.toValue = @(0.1f);
                break;
            case 2:
                //初始化动画并设置keyPath
                basicAni = [CABasicAnimation animationWithKeyPath:@"opacity"];
                //透明度
                basicAni.toValue=@(0.1f);
                break;
            case 3:
                //初始化动画并设置keyPath
                basicAni = [CABasicAnimation animationWithKeyPath:@"transform"];
                //3D
                basicAni.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2+M_PI_4, 1, 1, 0)];
                break;
            case 4:
                //初始化动画并设置keyPath
                basicAni = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
                //圆角
                basicAni.toValue=@(50);
                break;
     
            default:
                break;
        }
     
        //设置代理
        basicAni.delegate = self;
        //延时执行
        //basicAni.beginTime = CACurrentMediaTime() + 2;
        //动画时间
        basicAni.duration = 1;
        //动画节奏
        basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        //动画速率
        //basicAni.speed = 0.1;
        //图层是否显示执行后的动画执行后的位置以及状态
        //basicAni.removedOnCompletion = NO;
        //basicAni.fillMode = kCAFillModeForwards;
        //动画完成后是否以动画形式回到初始值
        basicAni.autoreverses = YES;
        //动画时间偏移
        //basicAni.timeOffset = 0.5;
        //添加动画
        [_aniLayer addAnimation:basicAni forKey:NSStringFromSelector(_cmd)];
    }
    //暂停动画
    -(void)animationPause{
        //获取当前layer的动画媒体时间
        CFTimeInterval interval = [_aniLayer convertTime:CACurrentMediaTime() toLayer:nil];
        //设置时间偏移量,保证停留在当前位置
        _aniLayer.timeOffset = interval;
        //暂定动画
        _aniLayer.speed = 0;
    }
    //恢复动画
    -(void)animationResume{
        //获取暂停的时间
        CFTimeInterval beginTime = CACurrentMediaTime() - _aniLayer.timeOffset;
        //设置偏移量
        _aniLayer.timeOffset = 0;
        //设置开始时间
        _aniLayer.beginTime = beginTime;
        //开始动画
        _aniLayer.speed = 1;
    }
    //停止动画
    -(void)animationStop{
        //[_aniLayer removeAllAnimations];
        //[_aniLayer removeAnimationForKey:@"groupAnimation"];
    }
     
    #pragma mark - CAAnimationDelegate
    -(void)animationDidStart:(CAAnimation *)anim{
     
    }
     
    -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
     
    }
     
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    @end
    

    CASpringAnimation

    CASpringAnimation是iOS9才引入的动画类,效果类似于UIView的spring动画,不过比其增加了质量,劲度系数等属性的扩展,继承于CABaseAnimation,用法也很简单:

    -(void)springAnimation{
        CASpringAnimation *springAni = [CASpringAnimation animationWithKeyPath:@"position"];
        springAni.damping = 2;
        springAni.stiffness = 50;
        springAni.mass = 1;
        springAni.initialVelocity = 10;
        springAni.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 400)];
        springAni.duration = springAni.settlingDuration;
        [_aniLayer addAnimation:springAni forKey:@"springAnimation"];
    }
    

    CAKeyframeAnimation

    关键帧动画和CABasicAnimation一样是CApropertyAnimation的子类,但是CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue)或者添加一个增量数值(byValue),而CAKeyframeAnimation使用values数组可以设置多个关键帧,同时可以利用path可以进行位置或者锚点的动画操作。操作起来也很简单:

    //关键帧动画
    -(void)keyframeAnimationWithTag:(NSInteger)tag{
        CAKeyframeAnimation *keyFrameAni = nil;
        if (tag == 6) {
            //晃动
            keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
            keyFrameAni.duration = 0.3;
            keyFrameAni.values = @[@(-(4) / 180.0*M_PI),@((4) / 180.0*M_PI),@(-(4) / 180.0*M_PI)];
            keyFrameAni.repeatCount=MAXFLOAT;
        }else if (tag == 7){
            //曲线位移
            keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position"];
            UIBezierPath *path = [UIBezierPath bezierPath];
            [path moveToPoint:_aniLayer.position];
            [path addCurveToPoint:CGPointMake(300, 500) controlPoint1:CGPointMake(100, 400) controlPoint2:CGPointMake(300, 450)];
            keyFrameAni.path = path.CGPath;
            keyFrameAni.duration = 1;
        }
        [_aniLayer addAnimation:keyFrameAni forKey:@"keyFrameAnimation"];
    }
    

    运行效果:


    image

    CATransition

    转场动画是一种显示样式向另一种显示样式过渡的效果,不太需要脑子就能制作出酷炫的效果,系统给出的效果也很多,不过谨慎使用私有API,防止被拒的悲剧。创建转场动画真的很简单:

    1.创建转场动画
    2.设置转场类型type,以及自类型subtype(也就是转场方向,不是所有的效果都有子类型)及其他属性。
    3.设置新的显示效果后,添加动画到图层。

    //转场动画
    -(void)transitionAnimation{
        CATransition *transtion = [CATransition animation];
        transtion.type = @"rippleEffect";
        transtion.subtype = kCATransitionFromLeft;//kCATransitionFromLeft  kCATransitionFromRight
        transtion.duration = 1;
        _transtionIndex++;
        if (_transtionIndex > 4) {
            _transtionIndex = 1;
        }
        _aniLayer.contents = (id)[UIImage imageNamed:[NSString stringWithFormat:@"%@.jpg",@(_transtionIndex)]].CGImage;
        [_aniLayer addAnimation:transtion forKey:@"transtion"];
    }
    

    运行效果:


    image

    CAAnimationGroup

    在我们实际开发中,我们可能需要更加复杂的复合运动,那么需要给图层加多个动画,动画组也就应运而生,创建动画组也很简单,首先创建单个动画,然后将创建的多个动画添加到动画组,最后将动画组添加图层上就可以啦。不要认为动画组诗简单的动画的集合,因为其他动画有的属性很多动画组也有,比如timingFunction,duration,repeatCount等,动画组和动画组的每一个元素都可以单独设置这些属性来实现一个不仅仅是单纯组合这么单纯的效果。(eg:生成一个动画,晃动位移1s到指定位置,并原地晃动2s,然后回到原位重新开始动画),代码如下:

    //动画组
    -(void)animationGroup{
        //晃动动画
        CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
        keyFrameAni.values = @[@(-(4) / 180.0*M_PI),@((4) / 180.0*M_PI),@(-(4) / 180.0*M_PI)];
        //每一个动画可以单独设置时间和重复次数,在动画组的时间基础上,控制单动画的效果
        keyFrameAni.duration = 0.3;
        keyFrameAni.repeatCount=MAXFLOAT;
        keyFrameAni.delegate = self;
        //
        //位移动画
        CABasicAnimation *basicAni = [CABasicAnimation animationWithKeyPath:@"position"];
        //到达位置
        basicAni.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
        //
        basicAni.duration = 1;
        basicAni.repeatCount = 1;
        //
        basicAni.removedOnCompletion = NO;
        basicAni.fillMode = kCAFillModeForwards;
        //设置代理
        basicAni.delegate = self;
        //动画时间
        basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        CAAnimationGroup *aniGroup = [CAAnimationGroup animation];
        aniGroup.animations = @[keyFrameAni,basicAni];
        aniGroup.autoreverses = YES;
        //动画的表现时间和重复次数由动画组设置的决定
        aniGroup.duration = 3;
        aniGroup.repeatCount=MAXFLOAT;
        //
        [_aniLayer addAnimation:aniGroup forKey:@"groupAnimation"];
    }
    

    动画节奏控制属性timingFunction:

    CA_EXTERN NSString * const kCAMediaTimingFunctionLinear //线性匀速
    CA_EXTERN NSString * const kCAMediaTimingFunctionEaseIn //慢进快出
    CA_EXTERN NSString * const kCAMediaTimingFunctionEaseOut //快进慢出
    CA_EXTERN NSString * const kCAMediaTimingFunctionEaseInEaseOut  //慢进慢出
    CA_EXTERN NSString * const kCAMediaTimingFunctionDefault  //默认
    

    当然你也可以自己创建对应的timingFunction,创建方式自寻。

    当前对象在非活动时间段的行为fillMode:

    CA_EXTERN NSString * const kCAFillModeForwards //动画结束后,保持着动画最后的状态
    CA_EXTERN NSString * const kCAFillModeBackwards //动画开始前,到达准备状态
    CA_EXTERN NSString * const kCAFillModeBoth  //动画开始前,进入准备状态,结束后,保持最后的状态
    CA_EXTERN NSString * const kCAFillModeRemoved  //动画完成后,移除,默认模式
    

    与transform和用的属性valueFunction:
    我们做一个旋转动画,我们会使用transform.rotation作为keyPath,但是它并不真实存在,这个属性就是因此而存在的,系统提供给了如下方式:

    CA_EXTERN NSString * const kCAValueFunctionRotateX
    CA_EXTERN NSString * const kCAValueFunctionRotateY
    CA_EXTERN NSString * const kCAValueFunctionRotateZ
    CA_EXTERN NSString * const kCAValueFunctionScale
    CA_EXTERN NSString * const kCAValueFunctionScaleX
    CA_EXTERN NSString * const kCAValueFunctionScaleY
    CA_EXTERN NSString * const kCAValueFunctionScaleZ
    CA_EXTERN NSString * const kCAValueFunctionTranslate
    CA_EXTERN NSString * const kCAValueFunctionTranslateX
    CA_EXTERN NSString * const kCAValueFunctionTranslateY
    CA_EXTERN NSString * const kCAValueFunctionTranslateZ
    

    举个例子:

    -(void)transformAnimation{
      //绕z轴旋转的动画
      CABasicAnimation * transformAni = [CABasicAnimation animationWithKeyPath:@"transform"];
      //从0度开始
      transformAni.fromValue = @0;
      //旋转到180度
      transformAni.toValue = [NSNumber numberWithFloat:M_PI];
      //duration
      transformAni.duration = 1;
      //设置valueFunction
      transformAni.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ];
      //添加动画
      [_aniLayer addAnimation:transformAni forKey:@"transformAnimation"];
    }
    

    其他取值大家可以自行试试。

    属性动画可以做动画的属性:

    opacity 透明度
    backgroundColor 背景颜色
    cornerRadius 圆角
    borderWidth 边框宽度
    contents 内容
    shadowColor 阴影颜色
    shadowOffset 阴影偏移量
    shadowOpacity 阴影透明度
    shadowRadius 阴影圆角
    ...
    rotation 旋转
    transform.rotation.x
    transform.rotation.y
    transform.rotation.z
    ...
    scale 缩放
    transform.scale.x
    transform.scale.y
    transform.scale.z
    ...
    translation 平移
    transform.translation.x
    transform.translation.y
    transform.translation.z
    ...
    position 位置
    position.x
    position.y
    ...
    bounds 
    bounds.size
    bounds.size.width
    bounds.size.height
    bounds.origin
    bounds.origin.x
    bounds.origin.y
    

    关键帧动画的计算模式calculationMode:
    当存在多个关键帧时,我们把每一个关键帧看为一个点,那么这些点可以是离散的,也可以直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算,那么就应用到了这个属性,具体取值如下:

    CA_EXTERN NSString * const kCAAnimationLinear  默认值,关键帧之间直接直线相连进行插值计算
    CA_EXTERN NSString * const kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示
    CA_EXTERN NSString * const kCAAnimationPaced  动画均匀进行,此时keyTimes和timingFunctions的设置失效
    CA_EXTERN NSString * const kCAAnimationCubic  关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义(http://en.wikipedia.org/wiki/Kochanek-Bartels_spline),这里的主要目的是使得运行的轨迹变得圆滑
    CA_EXTERN NSString * const kCAAnimationCubicPaced  在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的
    

    动画沿路径旋转方式rotationMode,默认为nil,系统提供了两种方式:

    CA_EXTERN NSString * const kCAAnimationRotateAuto  沿路径旋转
    CA_EXTERN NSString * const kCAAnimationRotateAutoReverse 沿路径反向颠倒旋转
    

    听起来比较不好理解,我们那之前的关键帧动画为例,看一波效果:

    设置keyFrameAni.rotationMode = kCAAnimationRotateAuto;,运行效果如下: image
    设置keyFrameAni.rotationMode = kCAAnimationRotateAutoReverse;,运行效果如下: image

    常用的转场动画类型:


    image

    方向子类型包括:


    image

    相关文章

      网友评论

          本文标题:CoreAnimation使用笔记

          本文链接:https://www.haomeiwen.com/subject/uxsjbftx.html