【问题标题】:CAGradientLayer properties not animating within UIView animation blockCAGradientLayer 属性在 UIView 动画块中没有动画
【发布时间】:2012-02-21 16:19:54
【问题描述】:

我觉得我忽略了一些基本的东西,但有什么比在互联网上出错更好的方法找到它?

我有一个相当基本的用户界面。我的UIViewController 的视图是一个子类,其+layerClassCAGradientLayer。根据用户的操作,我需要移动一些 UI 元素,并更改背景渐变的值。代码如下所示:

[UIView animateWithDuration:0.3 animations:^{
  self.subview1.frame = CGRectMake(...);
  self.subview2.frame = CGRectMake(...);
  self.subview2.alpha = 0;

  NSArray* newColors = [NSArray arrayWithObjects:
                         (id)firstColor.CGColor,
                         (id)secondColor.CGColor,
                         nil];
  [(CAGradientLayer *)self.layer setColors:newColors];
}];

问题是我在这个块中对子视图所做的更改动画效果很好(东西移动和淡入淡出),但对渐变颜色的更改却没有。它只是交换。

现在,the documentation does say 动画块中的核心动画代码不会继承块的属性(持续时间、缓动等)。但这是否根本没有定义动画事务? (文档的含义似乎是您将获得默认动画,而我没有。)

我是否使用明确的CAAnimation 来完成这项工作? (如果是,为什么?)

【问题讨论】:

    标签: ios uiview core-animation cagradientlayer


    【解决方案1】:

    这里似乎发生了两件事。第一个(正如 Travis 正确指出的那样,并且文档指出)是 UIKit 动画似乎对应用于 CALayer 属性更改的隐式动画没有任何影响。我认为这很奇怪(UIKit 必须使用核心动画),但它就是这样。

    这里有一个(可能非常愚蠢?)解决该问题的方法:

      NSTimeInterval duration = 2.0; // slow things down for ease of debugging
      [UIView animateWithDuration:duration animations:^{
        [CATransaction begin];
        [CATransaction setAnimationDuration:duration];
    
        // ... do stuff to things here ...
    
        [CATransaction commit];
      }];
    

    另一个关键是这个渐变层是我的视图层。这意味着我的视图是层的委托(如果渐变层只是一个子层,它就没有委托)。而-actionForLayer:forKey:UIView 实现为"colors" 事件返回NSNull。 (可能是每个不在特定 UIView 动画列表中的事件。)

    将以下代码添加到我的视图中将导致颜色变化按预期进行动画处理:

    - (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
    {
      id<CAAction> action = [super actionForLayer:layer forKey:event];
      if( [@"colors" isEqualToString:event]
          && (nil == action || (id)[NSNull null] == action) ) {
        action = [CABasicAnimation animationWithKeyPath:event];
      }
      return action;
    }
    

    【讨论】:

    • 很棒的发现!绝对不会想到这一点。
    【解决方案2】:

    您必须使用显式 CAAnimations,因为您正在更改 CALayer 的值。 UIViewAnimations 作用于 UIView 属性,但不能直接作用于它们的 CALayer 属性...

    实际上,您应该使用 CABasicAnimation 以便您可以访问其 fromValuetoValue 属性。

    以下代码应该适合您:

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        [UIView animateWithDuration:2.0f
                              delay:0.0f
                            options:UIViewAnimationCurveEaseInOut
                         animations:^{
                             CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"colors"];
                             animation.duration = 2.0f;
                             animation.delegate = self;
                             animation.fromValue = ((CAGradientLayer *)self.layer).colors;
                             animation.toValue = [NSArray arrayWithObjects:(id)[UIColor blackColor].CGColor,(id)[UIColor whiteColor].CGColor,nil];
                             [self.layer addAnimation:animation forKey:@"animateColors"];
                         }
                         completion:nil];
    }
    
    -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
        NSString *keyPath = ((CAPropertyAnimation *)anim).keyPath;
        if ([keyPath isEqualToString:@"colors"]) {
            ((CAGradientLayer *)self.layer).colors = ((CABasicAnimation *)anim).toValue;
        }
    }
    

    CAAnimations 有一个技巧,您必须在完成动画后显式设置属性的值。

    您可以通过设置委托来做到这一点,在本例中,我将其设置为调用动画的对象,然后覆盖其animationDidStop:finished: 方法以将 CAGradientLayer 的颜色设置包含为其最终值。

    您还必须在 animationDidStop: 方法中进行一些转换,以访问动画的属性。

    【讨论】:

    • 问题是,CALayer 属性具有隐式动画。 UIView 动画定义的动画属性似乎没有应用于 CALayer 更改,但这并不能解释为什么我没有看到颜色更改的 any 动画。
    • UIView 和 CALayer 都有隐式动画。当你触发一个 UIViewAnimation,并且你想在它的 CALayer 上触发一个动画时,你必须同时明确地这样做。这就是 CABasicAnimation 在 UIView 的动画中所做的:^{} 块...
    • 但关键是隐式动画没有发生,因为有问题的层是 view 的 层。这与是否在 UIView 动画块内进行更改完全不同。 (隐式动画的全部意义在于它们不需要显式动画块。)
    • 当然。无论如何,您在下面的答案是明确调用 CAAnimation 。我的答案实现了相同的结果,但也允许您自定义,只是提供相同结果的不同方法。您将动作应用于图层,而我正在向图层添加动画...
    • 不过,为什么是问题的重要部分。我从不怀疑我可以按照您概述的方式将 CABasicAnimation 扔到问题上,然后让它消失。但完全不清楚为什么这样做是必要。 (即使使用显式动画,您也需要做比实现预期效果更多的工作。)
    猜你喜欢
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多