UIView Animation 动画学习总结


目录
  • 这里和。其中很多属性在前面介绍的 UIView 动画部分我们也看到过,进一步验证了 UIView 的动画方法是对底层 CALayer 的一种封装。

    需要注意的一点是,上面我们使用了 position 属性, layer 的这个 position 属性和 View 的 frame 以及 bounds 属性都不相同,而是和 Layer 的 anchorPoint有关,可以由下面的公式计算得到:

    position.x = frame.origin.x + 0.5 * bounds.size.width;  
    position.y = frame.origin.y + 0.5 * bounds.size.height;
    

    关于 anchorPointposition 属性的以及具体计算的原理可以参考这篇文章。

    属性

    ·CABasicAnimation 的属性有下面几个:

    • beginTime
    • duration
    • fromValue
    • toValue
    • byValue
    • repeatCount
    • autoreverses
    • timingFunction

    可以看到,其中 beginTimedurationrepeatCount 等属性和上面在 UIView 中使用到的 durationUIViewAnimationOptionRepeat等选项是相对应的,不过这里的选项能够提供更多的扩展性。

    需要注意的是 fromValuetoValuebyValue 这几个选项,支持的设置模式有下面几种:

    • 设置 fromValuetoValue:从 fromValue 变化到 toValue
    • 设置 fromValuebyValue:从 fromValue 变化到 fromValue + byValue
    • 设置 byValuetoValue:从 toValue - byValue 变化到 toValue
    • 设置 fromValue: 从 fromValue 变化到属性当前值
    • 设置 toValue从属性当前值变化到 toValue
    • 设置 byValue从属性当前值变化到属性当前值 + toValue

    看起来挺复杂,其实概括起来基本就是 :如果某个值不设置,就是用这个属性当前的值

    另外,可以看到上面我们使用的:

    animation.toValue = @200;
    

    而不是直接使用 200,因为 toValue 之类的属性为 id 类型,或者像这样使用 @ 符号,或者使用:

    animation.toValue = [NSNumber numberWithInt:200];
    

    最后一个比较有意思的是 timingFunction 属性,使用这个属性可以自定义动画的运动曲线(节奏,pacing),系统提供了五种值可以选择:

    • kCAMediaTimingFunctionLinear 线性动画
    • kCAMediaTimingFunctionEaseIn 先快后慢
    • kCAMediaTimingFunctionEaseOut 先慢后快
    • kCAMediaTimingFunctionEaseInEaseOut 先慢后快再慢
    • kCAMediaTimingFunctionDefault 默认,也属于中间比较快

    此外,我们还可以使用 [CAMediaTimingFunction functionWithControlPoints] 方法来自定义运动曲线,这个网站提供了一个将参数调节可视化的效果,关于动画时间系统的具体介绍可以参考这篇文章。

    3.2 关键帧动画(CAKeyframeAnimation)

    同 UIView 中的类似,CALayer 层也提供了关键帧动画的支持,CAKeyFrameAnimationCABasicAnimation 都继承自 CAPropertyAnimation,因此它有具有上面提到的那些属性,此外,CAKeyFrameAnimation 还有特有的几个属性。

    values 和 keyTimes

    使用 valueskeyTimes 可以共同确定一个动画的若干关键帧,示例代码如下:

    CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];//在这里@"transform.rotation"==@"transform.rotation.z"
    NSValue *value1 = [NSNumber numberWithFloat:-M_PI/180*4];
    NSValue *value2 = [NSNumber numberWithFloat:M_PI/180*4];
    NSValue *value3 = [NSNumber numberWithFloat:-M_PI/180*4];
    
    anima.values = @[value1,value2,value3];
    // anima.keyTimes = @[@0.0, @0.5, @1.0];
    anima.repeatCount = MAXFLOAT;
    
    [_demoView.layer addAnimation:anima forKey:@"shakeAnimation"];
    

    可以看到上面这个动画共有三个关键帧,如果没有指定 keyTimes 则各个关键帧会平分整个动画的时间(duration)。

    path

    使用 path 属性可以设置一个动画的运动路径,注意 path 只对 CALayer 的 anchorPoint position 属性起作用另外如果你设置了 path ,那么 values 将被忽略。

    CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(SCREEN_WIDTH/2-100, SCREEN_HEIGHT/2-100, 200, 200)];
    anima.path = path.CGPath;
    anima.duration = 2.0f;
    [_demoView.layer addAnimation:anima forKey:@"pathAnimation"];
    

    3.3 动画组(CAAnimationGroup)

    组动画可以将一组动画组合在一起,所有动画对象可以同时运行,示例代码如下:

    CAAnimationGroup *group = [[CAAnimationGroup alloc] init];
    
    //1.基础动画一
    CABasicAnimation *animationOne = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    animationOne.toValue = @2.0;
    animationOne.duration = 1.0;
    
    //2.基础动画二
    CABasicAnimation *animationTwo = [CABasicAnimation animationWithKeyPath:@"position.x"];
    animationTwo.toValue = @400;
    animationTwo.duration = 1.0;
    
    [group setAnimations:@[animationOne, animationTwo]];
    [self.myView.layer addAnimation:group forKey:nil];
    

    需要注意的是,一个 group 组内的某个动画的持续时间(duration),如果超过了整个组的动画持续时间,那么多出的动画时间将不会被展示。例如一个 group 的持续时间是 5s,而组内一个动画持续时间为 10s ,那么这个 10s 的动画只会展示前 5s 。

    3.4 切换动画(CATransition)

    CATransition 可以用于 View 或 ViewController 直接的换场动画:

    self.myView.backgroundColor = [UIColor blueColor];
    CATransition *trans = [CATransition animation];
    trans.duration = 1.0;
    trans.type = @"push";
    [self.myView.layer addAnimation:trans forKey:nil];
    
    // 这句放在下面也可以
    // self.myView.backgroundColor = [UIColor blueColor];
    

    为什么改变颜色放在前后都可以呢?具体的解释可以参考 SO 上的这个回答。简单来说就是动画和绘制之间并不冲突。

    四、后记

    如果本文对你有一点帮助的话,欢迎收藏、点赞,感谢。文中如有不对之处,也欢迎大家在评论区指出,共勉。

相关