iOS 关键帧动画

作者: QiShare | 来源:发表于2018-11-05 10:55 被阅读72次

    级别:★★☆☆☆
    标签:「iOS CAKeyframeAnimation」「iOS 关键帧动画」「CAKeyframeAnimation values」「CAKeyframeAnimation path」
    作者: Xs·H
    审校: QiShare团队

    最近的项目需求涉及到一些动画效果。对于基本的动画,可以使用QiShare之前分享过的CABasicAnimation实现,而和路径相关的动画(例如图1的折线动画)可以使用CAKeyframeAnimation实现。

    图1 折线动画效果

    CAKeyframeAnimation和CABasicAnimation都是CAPropertyAnimation的子类。CABasicAnimation可以控制动画的起点(fromValue)和终点(toValue),而CAKeyframeAnimation可以控制动画的全过程。所以,可以将CABasicAnimation理解成只关注起点和终点的CAKeyframeAnimation。

    对比CABasicAnimation来说,CAKeyframeAnimation是通过控制动画的“关键帧”“步调”(关键帧执行的时间)来控制动画过程的。

    一、CAKeyframeAnimation使用“values”或“path”属性来控制动画的关键帧

    values:可选的NSArray对象,存放多个value,每个value就是一个keyframe(关键帧)。在动画过程中,关键帧会依序显示出来。
    path:可选的CGPathRef对象,指定动画的路径,可让CALayer的anchorPointposition按照路径变化。除了“moveTo”之外,路径中的每个点都是一个关键帧。如果需要沿路径匀速动画,需要将calculationMode属性设置为paced。当pathnil时,values属性被覆盖。

    二、CAKeyframeAnimation使用“keyTimes”属性来控制动画的步调

    keyTimes: 可选的NSArray对象,存放多个keyTime,每个keyTime都是[0, 1]区间内的浮点数所对应的NSNumber,与values中的关键帧一一对应,控制关键帧发生的时间。
    PS:当valuespath覆盖时,keyTimes作用于path。(path的优先级较高)

    三、使用CAKeyframeAnimation实现图1的折线动画效果

    为了辅助分析动画过程,我们为动画加上轨迹(后文只分析动画本身,不分析轨迹),如图2。

    图2 带轨迹的折线动画效果
    1) 像使用CABasicAnimation一样初始化CAKeyframeAnimation的对象
    // 初始化动画
    self.animation = [CAKeyframeAnimation animation];
    self.animation.keyPath = @"position";
    self.animation.delegate = self;
    self.animation.duration = 5.0;
    self.animation.repeatCount = 1.0;
    self.animation.removedOnCompletion = NO;
    self.animation.fillMode = kCAFillModeForwards;
    self.animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    
    2) 使用“values”和“keyTimes”属性设置动画的关键帧和步调
    // 设置动画的关键帧数组
    self.animation.values = @[[NSValue valueWithCGPoint:self.imageView.center],// 不能省略起点(1, 1)
                              [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 2, self.squareSide * 1}],// 右移1格
                              [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 2, self.squareSide * 5}],// 下移4格
                              [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 5, self.squareSide * 5}],// 右移3格
                              [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 5, self.squareSide * 7}]// 下移2格
                              ];
    // 设置动画的步调
    self.animation.keyTimes = @[@.0, @.1, @.5, @.8, @1.0];
    // self.animation.calculationMode = kCAAnimationPaced;// 可以替代上面的keyTimes实现匀速效果
    

    PS: 上述代码中的keyTimes是根据values的值进行设定的,以达到动画匀速的效果。若不设置keyTimes,动画时长(duration)将被平均分配给4段动画。

    3) 像使用CABasicAnimation一样为layer添加动画和移除动画
    if (start) {
        [self.imageView.layer addAnimation:_animation forKey:@"animation"];// 执行动画
    }
    else {
        [self.imageView.layer removeAnimationForKey:@"animation"];// 移除动画
    }
    

    上面有介绍到,path属性同样可以设置动画的关键帧,并且当path不为nil时会覆盖values
    所以,步骤2)可以替换为“path”“keyTimes”的方式。

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, self.imageView.center.x, self.imageView.center.y);
    CGPathAddLineToPoint(path, NULL, self.squareSide * 2, self.squareSide * 1);// 右移1格
    CGPathAddLineToPoint(path, NULL, self.squareSide * 2, self.squareSide * 5);// 下移4格
    CGPathAddLineToPoint(path, NULL, self.squareSide * 5, self.squareSide * 5);// 右移3格
    CGPathAddLineToPoint(path, NULL, self.squareSide * 5, self.squareSide * 7);// 下移2格
    self.animation.keyTimes = @[@.0, @.1, @.5, @.8, @1.0];
    // self.animation.calculationMode = kCAAnimationPaced;// 可以替代上面的keyTimes实现匀速效果
    self.animation.path = path;
    CGPathRelease(path);
    

    四、使用CAKeyframeAnimation实现曲线动画

    CAKeyframeAnimation的valuespath属性具有强大的功能,尤其是path,可以方便的制定自定义动画路径,比如图3的椭圆动画效果。

    图3 椭圆动画效果

    使用path制定上述椭圆路径的代码如下:

    CGRect drawRect = (CGRect){self.squareSide, self.squareSide, self.squareSide * 8, self.squareSide * 6};
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddEllipseInRect(path, NULL, drawRect);
    self.animation.keyTimes = @[@.0, @.25, @0.5, @0.75, @1.0];
    // self.animation.calculationMode = kCAAnimationPaced;
    self.animation.path = path;
    

    示例源码可从GitHub的QiShare开源库中获取。


    关注我们的途径有:
    QiShare(简书)
    QiShare(掘金)
    QiShare(知乎)
    QiShare(GitHub)
    QiShare(CocoaChina)
    QiShare(StackOverflow)
    QiShare(微信公众号)

    推荐文章:
    iOS 绘制渐变·基础篇
    iOS 绘制渐变·实例篇
    iOS 编写高质量Objective-C代码(七)
    奇舞周刊

    相关文章

      网友评论

        本文标题:iOS 关键帧动画

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