【问题标题】:How to make UI object responsive after CABasicAnimationCABasicAnimation 之后如何使 UI 对象响应
【发布时间】:2014-01-16 10:43:56
【问题描述】:

在 CABasicAnimation 滑入和弹跳后,我无法找到一种方法让我的 UI 对象 (UISegmentedControl) 触摸响应。我怎样才能做到这一点?

我知道 UI 对象在移动后位于表示树中。但我真的很喜欢 CABasicAnimation 提供的 setTimingFunction 功能,我只是无法使用 UIView 动画获得如此平滑的反弹。

动画 GIF 示例(循环):

我在 viewDidLoad 中使用的代码

CABasicAnimation *startAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
[startAnimation setFromValue:[NSNumber numberWithFloat:0]];
[startAnimation setToValue:[NSNumber numberWithFloat:slidingUpValue]];
[startAnimation setDuration:1.0];
startAnimation.fillMode = kCAFillModeForwards;
startAnimation.removedOnCompletion = NO;
[startAnimation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.3 :1.8]];
[[gameTypeControl layer] addAnimation:startAnimation forKey:nil];

【问题讨论】:

  • 感谢代码样式修复 Mani。看起来好多了。

标签: ios objective-c core-animation cabasicanimation


【解决方案1】:

出了什么问题

问题是这两行代码,不理解使用它们的副作用:

startAnimation.fillMode = kCAFillModeForwards;
startAnimation.removedOnCompletion = NO;

第一行将动画配置为在动画完成后继续显示结束值(您可以在my little cheat sheet 中看到 fillMode 和其他与时间相关的属性的可视化)。

第二行将动画配置为在完成后保持附加到图层。

这听起来不错,但缺少核心动画的一个重要部分:添加到图层的动画永远不会影响模型,只会影响演示Core Animation Programming Guide 在“Core Animation Basics”部分的第二页上提到了这一点:

图层对象的数据和状态信息与该图层内容在屏幕上的视觉呈现分离。

动画发生在一个单独的层上,即你在屏幕上看到的表示层。如果您在动画期间打印出动画属性的值,它们根本不会改变。

在动画过程中,演示文稿和模型之间存在差异,但动画可能很短,并且动画完成后这种差异就会消失,所以这并不重要......除非动画没有'不要走开。然后差异仍然存在,现在您必须处理两个地方的数据不同步。

如何解决这个问题

可以说一切看起来都很好,只是命中测试是错误的。让我们进行补丁命中测试!将命中测试更改为使用段控件层的表示层,命中测试将起作用。太好了,对吧?这就像把一个石膏放在另一个上面,而不是从根源上解决问题。

如何消除副作用

这真的很简单:不要使用这些线条并在动画完成后删除它们。有人可能会说 Apple 已在幻灯片和示例代码中使用了这种技术(不删除动画),因此这是 Apple 推荐的,但有一个微妙的细节很容易被忽略:

当 Apple 在 WWDC 2007 上推出 Core Animation 时,他们使用这种技术为被移除的层制作动画(例如,淡出)。以下引用来自 Session 211 - 将核心动画添加到您的应用程序:

  • 要动画层移除,使用动画
    fillMode = forwards, removedOnCompletion = NO
    • 动画代理可以移除图层

在这种情况下,不移除动画是完全可以的,因为它可能会导致层在从层层次结构中移除之前的一帧跳回其原始大小、不透明度等。正如他们在上面的幻灯片中所说:“动画代理可以删除图层”(即:进行清理)。

在其他情况下,没有人进行清理,而您会因为两个地方的数据不同步而陷入混乱(如上所述)。

解决方案是动画的不同方法

在构建动画时,我尝试这样思考:

如果您的动画莫名其妙地消失了,那么模型值应该是预期的结束状态。

应用于您的示例,分段控件正在向其最终位置移动以停在那里并停留在那里。在这种情况下,分段控件的实际位置应该是结束位置。即使动画不存在,应用程序也应该可以工作。

那么动画呢?不是从 0 偏移量动画到某个偏移量,而是将其反转并从某个负偏移量动画到 0 偏移量。

CABasicAnimation *startAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
[startAnimation setFromValue:@(-slidingUpValue)]]; // these two changed 
[startAnimation setToValue:@(0.0)];                // places with each other
[startAnimation setDuration:1.0];
// no fill mode
// animation is removed on completion
[startAnimation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.3 :1.8]];
[[gameTypeControl layer] addAnimation:startAnimation forKey:@"Move in game type control from bottom"]; // I like adding descriptive keys for easier debugging

【讨论】:

  • 这很完美!非常感谢您花这么多时间回答我的问题。这些信息帮助我更多地了解这个惊人的主题 (CA) 并缩短了我的代码。我也很高兴我不需要使用 UIView Animation 来尝试复制 setTimingFunction 之类的效果。你刚刚完成了我的一周!
  • 优秀的答案大卫! (+1) 你是 SO 社区的资产。
猜你喜欢
  • 2012-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多