UIView.layer.presentationLayer 返回最终值(而不是当前值)

Posted

技术标签:

【中文标题】UIView.layer.presentationLayer 返回最终值(而不是当前值)【英文标题】:UIView.layer.presentationLayer returns final value (rather than current value) 【发布时间】:2014-03-30 07:38:10 【问题描述】:

这是 UIView 子类中的一些相关代码:

- (void) doMyCoolAnimation 
  CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
  anim.duration = 4;
  [self.layer setValue:@200 forKeyPath:anim.keyPath];
  [self.layer addAnimation:anim forKey:nil];


- (CGFloat) currentX 
  CALayer* presLayer = self.layer.presentationLayer;
  return presLayer.position.x;

当我在动画运行时使用[self currentX] 时,我得到200(结束值)而不是介于 0(开始值)和200 之间的值。是的,动画对用户是可见的,所以我在这里真的很困惑。

这是我调用 doMyCoolAnimation: 的代码,以及 1 秒后调用 currentX 的代码。

[self doMyCoolAnimation];

CGFloat delay = 1; // 1 second delay
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^
  NSLog(@"%f", [self currentX]);
);

有什么想法吗?

【问题讨论】:

如果您在动画添加到图层后立即调用 getter,您应该得到接近 0.4 的值。尝试将您的 get 包裹在 dispatch_after() @CodaFi 我知道这一点并且已经在使用dispatch_after()。我正在检查一个有效的时间,但presentationLayer 假装它是一个模型层(我困惑的根源)。 从动画中分离出KVC setter,然后从KVC setter中分离出动画,看看我的意思。在其当前形式下,动画将不执行任何操作,KVC 设置器将使图层以默认的隐式动画速度弹到其下一个位置。 【参考方案1】:

我不知道在动画代码中使用 KVC 设置器的想法从何而来,但这就是动画本身的用途。您基本上是在告诉图层树立即使用此行更新到新位置:

[self.layer setValue:@200 forKeyPath:anim.keyPath];

然后想知道为什么层树不会使用没有开始或结束值的动画动画到该位置。没有什么可以动画的!根据需要设置动画的 toValuefromValue 并放弃设置器。或者,如果您希望使用隐式动画,请保留 setter,但放弃动画并通过更改图层的 speed 来设置其持续时间。

【讨论】:

动画可见正在发生。或者您是否声称如果我使用 CABasicAnimation 的 toValue 而不是 implicit animation,则presentationLayer 将被修复? 隐式动画和显式动画......这没有任何意义。 CALayer 将尽最大努力为所有属性更改设置动画,但是当您尝试提交对图层不执行任何操作的动画时,它将什么也不做。我的意思是,setValue:forKeyPath: 并不是像您试图做的那样创建显式动画的步骤。 This guy does what I'm doing。在我想访问presentationLayer之前,它一直对我有用。 从您的代码的外观来看,您根本没有遵循他的示例。在那篇博文中没有提到通过 KVC setter。 好吧,我想通了。将fromValue 添加到CABasicAnimation 使presentationLayer 返回正确的值!感谢您的帮助@CodaFi。【参考方案2】:

我的 UIView 层的presentationLayer 没有给我当前的值。相反,它给了我动画的最终值。

 

要解决这个问题,我所要做的就是添加...

anim.fromValue = [self.layer valueForKeyPath:@"position.x"];

...到我的 doMyCoolAnimation 方法 BEFORE 我将最终值设置为:

[self.layer setValue:@200 forKeyPath:@"position.x"];

 

所以最后,doMyCoolAnimation 看起来像这样:

- (void) doMyCoolAnimation 
  CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position.x"];
  anim.duration = 4;
  anim.fromValue = [self.layer valueForKeyPath:anim.keyPath];
  [self.layer setValue:@200 forKeyPath:anim.keyPath];
  [self.layer addAnimation:anim forKey:nil];

【讨论】:

【参考方案3】:

正如 CodaFi 所说,您创建动画的方式是错误的。

要么使用显式动画,使用 CABasicAnimation,要么使用隐式动画,直接更改图层的属性,而不是使用 CAAnimation 对象。不要将两者混为一谈。

当您创建 CABasicAnimation 对象时,您在动画上使用 setFromValue 和/或 setToValue。然后动画对象负责为表示层中的属性设置动画。

【讨论】:

以上是关于UIView.layer.presentationLayer 返回最终值(而不是当前值)的主要内容,如果未能解决你的问题,请参考以下文章