CAGradientLayer属性不在UIView动画块中设置动画

时间:2012-02-21 16:19:55

标签: ios uiview core-animation cagradientlayer

我有一种感觉,我忽略了一些基本的东西,但有什么更好的方式来找到它而不是在互联网上出错?

我有一个相当基本的用户界面。我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动画块中的Core Animation代码不会继承块的属性(持续时间,缓动等)。但是,根本没有定义动画交易吗? (文档的含义似乎是你会得到一个默认动画,我得不到。)

使用显式CAAnimation来完成这项工作吗? (如果是这样,为什么?)

2 个答案:

答案 0 :(得分:13)

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

对于这个问题,这是一个(可能非常愚蠢?)解决方法:

  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];
  }];

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

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

"colors"

答案 1 :(得分:1)

您必须使用显式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:方法中进行一些转换,以访问动画的属性。

相关问题