当我在animationDidStart中设置结束值时,CABasicAnimation没有插值:

Posted

技术标签:

【中文标题】当我在animationDidStart中设置结束值时,CABasicAnimation没有插值:【英文标题】:CABasicAnimation not interpolating when I set the end value in animationDidStart: 【发布时间】:2014-03-02 02:28:59 【问题描述】:

我已经为 CABasicAnimation 实例的紧凑创建做了一个包装器。 它通过 UIView 的类别作为名为 change:from:to:in:ease:delay:done: 的实例方法来实现。例如,我可以这样做:

[self.logo
  change:@"y"
  from:nil            // Use current self.logo.layer.position.y
  to:@80
  in:1                // Finish in 1000 ms
  ease:@"easeOutQuad" // A selector for a CAMediaTimingFunction category method
  delay:0
  done:nil];

问题

当 CABasicAnimation 启动时,animationDidStart: 处理将 self.logo.layer.position.y 设置为 80(结束值)。在它像这样工作之前,我尝试使用animationDidStop:finished: 做同样的事情,但在完成动画后发现图层闪烁。 现在,图层直接到达最终值,不会发生插值。我在 UIView 类别中实现了animationDidStart:,如下所示:

- (void)animationDidStart:(CAAnimation *)animation

    [self.layer
        setValue:[animation valueForKey:@"toValue"]
        forKeyPath:[animation valueForKey:@"keyPath"]];

我设置结束值是为了使模型层与表示层匹配(换句话说,防止重置回开始位置)。

这是change:from:to:in:ease:delay:done:的实现...

- (CABasicAnimation*) change:(NSString*)propertyPath
                        from:(id)from
                          to:(id)to
                          in:(CGFloat)seconds
                        ease:(NSString*)easeName
                       delay:(CGFloat)delay
                        done:(OnDoneCallback)done

  NSString* keyPath = [app.CALayerAnimationKeyPaths objectForKey:propertyPath];
  if (keyPath == nil) keyPath = propertyPath;
  CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:keyPath];
  if (delay > 0) animation.beginTime = CACurrentMediaTime() + delay;
  if (easeName != nil) animation.timingFunction = [CAMediaTimingFunction performSelector:NSSelectorFromString(easeName)];
  if (from != nil) animation.fromValue = from;
  animation.toValue = to;
  animation.duration = seconds;
  animation.delegate = self;
  [self.layer setValue:done forKey:@"onDone"];
  [self.layer addAnimation:animation forKey:keyPath];
  return animation;

在上面代码的第一行,这是我用来将属性快捷方式转换为真正的keyPath的NSDictionary。这样我就可以每次只输入@"y" 而不是@"position.y"

app.CALayerAnimationKeyPaths = @
  @"scale": @"transform.scale",
  @"y": @"position.y",
  @"x": @"position.x",
  @"width": @"frame.size.width",
  @"height": @"frame.size.height",
  @"alpha": @"opacity",
  @"rotate": @"transform.rotation"
;

有什么问题吗?

【问题讨论】:

【参考方案1】:

我认为,您所看到的是预期的行为。在该属性的动画开始后,您正在设置一个动画属性。这实际上是最常见和推荐的方式来准确地完成您所看到的事情,即取消动画并立即跳到最终位置。所以你故意在动画开始的那一刻取消你自己的动画。

如果这不是您想要的,请不要这样做。只需将动画属性设置为其最终值之前将动画附加到图层 - 当然要小心,不要在这样做时触发隐式动画。

【讨论】:

所以你是说我应该把[self.layer setValue:to forKeyPath:keyPath];放在[self.layer addAnimation:animation forKey:keyPath];之前? 请参阅我的书,了解设置 CABasicAnimation 的规范方法以及它为何如此工作:apeth.com/iosBook/ch17.html#_using_a_cabasicanimation 之前不一定要正确。无论如何,在运行循环结束之前什么都不会发生。可能是您在方法中做的第一件事。其实如果是这样就更简单了,因为这样你就已经把模型层和表现层都设置好了,你就不需要设置from值和to值了。 当我想更改 layer.position.y 时,我仍然看不到插值。我只能通过layer.position 制作动画吗? 也许您只是对模板代码感到困惑。以正常方式尝试:NSString* key = @"position.y"; [self.lay setValue:@200 forKeyPath:key]; CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:key"]; ba.duration = 3; [self.lay addAnimation:ba forKey:key]; 工作正常。

以上是关于当我在animationDidStart中设置结束值时,CABasicAnimation没有插值:的主要内容,如果未能解决你的问题,请参考以下文章

当我在代码中设置属性时,情节提要选项是启用还是禁用是不是重要?

使用javascript在谷歌道路API中设置开始和结束位置

为啥 UIScrollView contentSize 在 IB 中被忽略,但当我在 viewDidAppear 方法中设置它时有效?

当我在构建选项中设置 iPhone 开发人员代码签名身份时,为啥 XCode 会继续尝试安装临时配置文件?

如何使用 Ionic (Angular) 在一个对话框中设置开始时间、结束时间和持续时间

当我在 Swift 2.0 中设置 UILabel 标题时的 EXC_BAD_INSTRUCTION