我有一种感觉,我忽略了一些基本的东西,但有什么更好的方式来找到它而不是在互联网上出错?
我有一个相当基本的用户界面。我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];
}];
问题是我在这个块中对子视图所做的更改动画就好了(东西移动和淡化),但渐变颜色的变化却没有。它只是交换。
现在,the documentation does say动画块中的Core Animation代码不会继承块的属性(持续时间,缓动等)。但是,根本没有定义动画交易吗? (文档的含义似乎是你会得到一个默认动画,我得不到。)
我 使用显式CAAnimation
来完成这项工作吗? (如果是这样,为什么?)
答案 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,以便访问其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:
方法中进行一些转换,以访问动画的属性。