Ios CAGradientLayer属性未在UIView动画块中设置动画

Ios CAGradientLayer属性未在UIView动画块中设置动画,ios,uiview,core-animation,cagradientlayer,Ios,Uiview,Core Animation,Cagradientlayer,我有一种感觉,我忽略了一些基本的东西,但是有什么比在互联网上犯错更好的方法来发现它呢 我有一个相当基本的用户界面。myUIViewController的视图是一个子类,它的+layerClass是CAGradientLayer。根据用户的操作,我需要移动一些UI元素,并更改背景渐变的值。代码如下所示: [UIView animateWithDuration:0.3 animations:^{ self.subview1.frame = CGRectMake(...); self.subv

我有一种感觉,我忽略了一些基本的东西,但是有什么比在互联网上犯错更好的方法来发现它呢

我有一个相当基本的用户界面。my
UIViewController
的视图是一个子类,它的
+layerClass
CAGradientLayer
。根据用户的操作,我需要移动一些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];
}];
问题是,我在这个块中对子视图所做的更改动画效果很好(内容移动和淡出),但对渐变颜色的更改却没有。它只是交换

现在,动画块中的核心动画代码将不会继承块的属性(持续时间、缓和度等)。但是这种情况是否根本不定义动画事务?(这些文档的含义似乎是,您将获得一个默认动画,而我没有得到任何动画。)


我是否必须使用显式
CAAnimation
来实现此功能?(如果是,为什么?

您必须使用显式CAAnimations,因为您正在更改CALayer的值。 UIViewAnimations在UIView属性上工作,但不直接在其CALayer属性上工作

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

以下代码应适用于您:

-(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:
方法中进行一些转换,以访问动画的属性。

这里似乎有两件事。第一个问题(正如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;
}
-(id)actionForLayer:(CALayer*)layer-forKey:(NSString*)事件
{
id action=[super actionForLayer:layer-forKey:event];
if([@“colors”IsequalString:event]
&&(nil==操作| |(id)[NSNull null]==操作)){
动作=[CABasicAnimation animationWithKeyPath:event];
}
返回动作;
}

问题是,CALayer属性具有隐式动画。UIView动画定义的动画属性似乎没有应用于CALayer更改,但这并不能解释为什么我没有看到任何颜色更改的动画。UIView和CALayer都有隐式动画。当您触发UIViewAnimation,并且希望在其CALayer上触发动画时,必须同时显式执行此操作。这就是在UIView的动画:^{}块中的CABASICANIATION所做的,但关键是隐式动画没有发生,因为所讨论的层是视图的层。这与是否在UIView动画块内部进行更改是完全不同的。(隐式动画的全部要点是它们不需要显式动画块。)当然。不管怎么说,你在下面的回答是明确的,在最后是一个警告。我的答案实现了相同的结果,但也允许您自定义,只是提供相同结果的不同方法。你将一个动作应用到一个层,而我正在给层添加一个动画…但是为什么是问题的重要部分。我从来没有怀疑过,我可以用你概述的方式,对这个问题进行一番解释,然后让它消失。但根本不清楚为什么这样做是必要的。(即使使用显式动画,您也要做比达到预期效果所需的更多的工作。)奇妙的发现!我永远不会想到这一点。