首页 文章

使用CABasicAnimation不止一次旋转UIImageView

提问于
浏览
13

我正在使用CABasicAnimation顺时针旋转 UIImageView 90度,但我需要让它在最初90度旋转后从其位置再旋转90度 .

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.duration = 10;
animation.additive = YES;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.fromValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(0)];
animation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(90)];
[_myview.layer addAnimation:animation forKey:@"90rotation"];

使用上面的代码最初工作,图像保持90度角 . 如果我再次调用它使其再旋转90度,则动画开始时跳回0并旋转90度,而不是90度到180度 .

我的印象是 animation.additive = YES; 会导致进一步的动画使用当前状态作为起点 .

有任何想法吗?

2 回答

  • 63

    传递角度的增量值,请参阅我的代码

    static int imgAngle=0;
    - (void)doAnimation
    {
      CABasicAnimation *animation = [CABasicAnimation   animationWithKeyPath:@"transform.rotation.z"];
       animation.duration = 5;
      animation.additive = YES;
      animation.removedOnCompletion = NO;
      animation.fillMode = kCAFillModeForwards;
      animation.fromValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(imgAngle)];
      animation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(imgAngle+90)];
     [self.imgView.layer addAnimation:animation forKey:@"90rotation"];
    
      imgAngle+=90;
      if (imgAngle>360) {
          imgAngle = 0;
      }
    }
    

    以上代码仅供参考 . 它没有经过测试

  • 6

    tl;dr: 滥用 removeOnCompletion = NO 非常容易,大多数人都没有意识到这样做的后果 . 正确的解决方案是更改模型值"for real" .


    首先:我不是在试图判断或对你有意义 . 我一遍又一遍地看到同样的误解,我可以看出它为什么会发生 . 通过解释事情发生的原因,我希望每个遇到相同问题并看到这个答案的人都能更多地了解他们的代码在做什么 .

    出了什么问题

    我的印象是animation.additive = YES;会导致进一步的动画使用当前状态作为起点 .

    这是非常正确的,它正是发生的事情 . 从这个意义上说,电脑很有趣 . 他们总是正是你告诉他们的,而不是你想让他们做什么 .

    removeOnCompletion = NO可以是一个婊子

    在你的情况下,反派是这行代码:

    animation.removedOnCompletion = NO;
    

    在动画完成后,通常会误用动画的最终值 . 唯一的问题是它不会从视图中删除动画 . Core Animation中的动画不会改变它们动画的基础属性,它们只是在屏幕上制作动画 . 如果你在动画期间查看实际值,你将永远不会看到它的变化 . 相反,动画适用于所谓的表示层 .

    通常,当动画完成时,它将从图层中移除,表示层将消失,模型图层将再次出现在屏幕上 . 但是,当您将动画附加到图层时,所有内容都应该在屏幕上显示,但是您已经介绍了属性所说的变换与图层在屏幕上的旋转方式之间的区别 .

    当您将动画配置为添加时,意味着将from和to值添加到现有值,就像您所说的那样 . 问题是该属性的值为0.您永远不会更改它,只需为其设置动画即可 . 下次尝试将该动画添加到同一图层时,该值仍然不会被更改,但动画正在完成配置要执行的操作:“从模型的当前值添加动画” .

    解决方案

    跳过那行代码 . 结果是旋转不会粘住 . 让它坚持下去的更好方法是改变模型 . 在设置旋转动画之前设置旋转的新结束值,以便在移除动画时模型看起来应该如此 .

    byValue就像魔术一样

    CABasicAnimation 上有一个非常方便的属性(我将要使用),它被称为 byValue ,可用于制作相对动画 . 它可以与 toValuefromValue 组合以执行许多不同类型的动画 . 不同的组合都在其文档中指定(在该部分下) . 我将要使用的组合是:

    byValue和toValue都是非零的 . 在(toValue - byValue)和toValue之间插值 .

    一些实际的代码

    显式 toValue 为0时,动画从"currentValue-byValue"发送到"current value" . 通过更改模型,第一个当前值是结束值 .

    NSString *zRotationKeyPath = @"transform.rotation.z"; // The killer of typos
    
    // Change the model to the new "end value" (key path can work like this but properties don't)
    CGFloat currentAngle = [[_myview.layer valueForKeyPath:zRotationKeyPath] floatValue];
    CGFloat angleToAdd   = M_PI_2; // 90 deg = pi/2
    [_myview.layer setValue:@(currentAngle+angleToAdd) forKeyPath:zRotationKeyPath]; 
    
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:zRotationKeyPath];
    animation.duration = 10;
    // @( ) is fancy NSNumber literal syntax ...
    animation.toValue = @(0.0);        // model value was already changed. End at that value
    animation.byValue = @(angleToAdd); // start from - this value (it's toValue - byValue (see above))
    
    // Add the animation. Once it completed it will be removed and you will see the value
    // of the model layer which happens to be the same value as the animation stopped at.
    [_myview.layer addAnimation:animation forKey:@"90rotation"];
    

    小免责声明:

    我没有运行这段代码,但我相当确定它应该运行它并且我没有做任何错别字 . 如果我这样做,请纠正我 . 整个讨论仍然有效 .

相关问题