• Core Animation (1)


    Core Animation 是iOS动画技术的根本。 视图动画和隐式图层动画都仅仅是Core Animation的方便包装。 Core Animation 是显式图层动画,让你创造更加绚丽的动画。

    让视图的根图层执行动画是一种图层动画,而不是视图动画--因此不会对视图的子视图进行自动布局,所以我们常常喜欢使用视图动画,而不是图层动画。


    CABasicAnimation and Its Inheritance

    通过Core Animation驱动一个属性执行动画的最简单方法就是使用CABasicAnimation对象。通过继承CABasicAnimation,可以发挥它的强大力量,所以下面我只会讲解CABasicAnimation的继承,你可以体会到所有目前我们看到的属性动画都体现在CABasicAnimation实例中。

    CAAnimation

    CAAnimation是一个抽象类,这意味着你将永远只能用它的一个子类。有些CAAnimation的功能来自于它实现的CAMediaTiming协议,协议中定义了8个属性。

    • animation

      一个类方法,创建一个动画对象的方便形式

    • delegate

      这个委托的消息是 animationDidStart: and animationDidStop:finished:。

      一个CAAnimation实例会保留它的委托; 这是非常不寻常的行为,如果你不明白它(我的经验之谈可能会导致麻烦。另外,为了让你的代码在动画结束时调用,不要设置一个委托,而是在配置动画之前,调用CATransaction 的类方法setCompletionBlock:。

    • duration, timingFunction

      动画的长度和它的时间函数(一个 CAMediaTiming 函数)。 持续时间为0(默认值)表示 0.25秒,除非通过事务来覆盖。

    • autoreverses, repeatCount, repeatDuration, cumulative

      前两个是类似与UIView的动画。该repeatDuration属性是用不同的方式来管理重复,指定重复应该持续多久而不是应该重复多少次;不要同时指定repeatCount和repeatDuration。如果cumulative属性时YES,一个重复的动画时从上一个重复的动画结束的地方开始每个重复(而不是每次都跳到开始的值来重复)。

    • beginTime

      动画开始前的延时。为了从现在开始延时一个动画,调用 CACurrentMediaTime 和添加一个指定的延时秒数。这个延时不会计算在动画的持续时间里。

    • timeOffset

      timeOffset属性有点难理解,它对时间进行偏移(offset)。具体的内容,又一篇文章做了解析: http://www.cocoachina.com/programmer/20131218/7569.html

    CAAnimation,连同其所有的子类,实现了KVC,允许您通过一个key来设置和获取任意值,类似的CALayer和CATransaction。

    CAPropertyAnimation

    CAPropertyAnimation是CAAnimation的一个子类,也是抽象的,添加了下面的:

    • keyPath

      通过CAPropertyAnimation类方法 animationWithKeyPath: ,传入一个keyPath来创建一个实例。

    • additive

      如果是YES,由动画所提供的值将会被添加到当前显示层的值。

    • valueFunction

      转换一个你提供的简单标量值到一个transform。

    CABasicAnimation

    CABasicAnimation是CAPropertyAnimation的一个子类(不是抽象的),添加了下面的:

    • fromValue, toValue

      动画的起始和结束值。这些值必须是对象,所以数字和结构体将必须使用NSNumber和NSValue包装。如果不设置fromValue和toValue,将会使用以前和现在的值。如果只是提供fromValue或toValue的一个,另一个使用该属性的当前值。

    • byValue

      通过设置这个值和 fromValue 、toValue中的中的一个,系统会自动帮你通过加法或减法来算出另一个值。如果你只设置了byValue,那么fromValue就是属性的当前值。


    Using a CABasicAnimation

    既然已经构造和配置了一个CABasicAnimation,那么我们执行它的方式就是把它添加到一个图层上。 通过CALayer的实例方法 addAnimation:forKey:(后面会讲这个key的作用,现在我们只需传nil就可以了)。

    但是,CAAnimation只是一个动画,动画播放完了,你的图层仍然会在动画开始前的位置,什么都没有改变,你需要保证图层与动画的结束值对应上。毕竟我们是使用显式动画,更加底层,需要多加小心。

    一般的步骤是:

    1. 捕获需要改变的图层属性的开始和结束值。

    2. 改变图层的属性为它的动画结束值,如果需要防止隐式动画,可以首先调用

    setDisableActions:方法。

    1. 使用你刚刚捕获的值和这个属性对应的keyPath来构造显式动画。

    2. 添加显式动画到图层上。

    下面就是对我们的箭头执行旋转动画:

    // capture the start and end values
    CATransform3D startValue = arrow.transform;
    CATransform3D endValue =
        CATransform3DRotate(startValue, M_PI/4.0, 0, 0, 1);
    // change the layer, without implicit animation
    [CATransaction setDisableActions:YES];
    arrow.transform = endValue;
    // construct the explicit animation
    CABasicAnimation* anim =
        [CABasicAnimation animationWithKeyPath:@"transform"];
    anim.duration = 0.8;
    CAMediaTimingFunction* clunk =
        [CAMediaTimingFunction functionWithControlPoints:.9 :.1 :.7 :.9];
    anim.timingFunction = clunk;
    anim.fromValue = [NSValue valueWithCATransform3D:startValue];
    anim.toValue = [NSValue valueWithCATransform3D:endValue];
    // ask for the explicit animation
    [arrow addAnimation:anim forKey:nil];
    

    一旦你知道了完整形式,你会发现,在许多情况下,它可以浓缩。例如,当fromValue和toValue都没有设置,该属性的以前和现在值会自动使用(这是可能的,因为在表现层有了新的值时,它仍然由原来的属性的值)。因此,在这种情况下,没有必要对其进行设置,因此没有必要事先捕捉开始和结束值。这里的浓缩版:

    [CATransaction setDisableActions:YES];
    arrow.transform =
        CATransform3DRotate(arrow.transform, M_PI/4.0, 0, 0, 1);
    CABasicAnimation* anim =
        [CABasicAnimation animationWithKeyPath:@"transform"];
    anim.duration = 0.8;
    CAMediaTimingFunction* clunk =
        [CAMediaTimingFunction functionWithControlPoints:.9 :.1 :.7 :.9];
    anim.timingFunction = clunk;
    [arrow addAnimation:anim forKey:nil];
    

    让我们的箭头出现快速振动:

    // capture the start and end values
    CATransform3D nowValue = arrow.transform;
    CATransform3D startValue =
        CATransform3DRotate(nowValue, M_PI/40.0, 0, 0, 1);
    CATransform3D endValue =
        CATransform3DRotate(nowValue, -M_PI/40.0, 0, 0, 1);
    // construct the explicit animation
    CABasicAnimation* anim =
        [CABasicAnimation animationWithKeyPath:@"transform"];
    anim.duration = 0.05;
    anim.timingFunction =
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    anim.repeatCount = 3;
    anim.autoreverses = YES;
    anim.fromValue = [NSValue valueWithCATransform3D:startValue];
    anim.toValue = [NSValue valueWithCATransform3D:endValue];
    // ask for the explicit animation
    [arrow addAnimation:anim forKey:nil];
    

    的确,上面的代码还可以简化,我们可以无需基于当前新的旋转值方向计算下一个旋转值,只需设置additive为YES;这意味着,动画的属性值被添加到我们现有的属性值,所以它们是相对的,不是绝对的。

    CABasicAnimation* anim =
        [CABasicAnimation animationWithKeyPath:@"transform"];
    anim.duration = 0.05;
    anim.timingFunction =
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    anim.repeatCount = 3;
    anim.autoreverses = YES;
    anim.additive = YES;
    anim.valueFunction =
        [CAValueFunction functionWithName:kCAValueFunctionRotateZ];
    anim.fromValue = @(M_PI/40);
    anim.toValue = @(-M_PI/40);
    [arrow addAnimation:anim forKey:nil];
  • 相关阅读:
    使用BackgroundWorker组件进行异步操作编程《转》
    C#多线程控制进度条之长任务操作《转》
    模态进度条窗体实现<转>
    dev xtraReports使用《转》
    客户端IP
    WebService获取服务端硬件信息和客户端IP,MAC,浏览器信息,所在城市《转》
    c#多线程 Invoke方法的使用<转>
    C# windowform进度条《转》
    XtraReports 打印控件的简单使用《转》
    hdu Marriage Match II
  • 原文地址:https://www.cnblogs.com/YungMing/p/4032646.html
Copyright © 2020-2023  润新知