如何在CABasicAnimation之后使UI对象响应

Tro*_*y R 5 core-animation objective-c cabasicanimation ios

在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];
Run Code Online (Sandbox Code Playgroud)

Dav*_*ist 30

什么地方出了错

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

startAnimation.fillMode = kCAFillModeForwards;
startAnimation.removedOnCompletion = NO;
Run Code Online (Sandbox Code Playgroud)

第一行配置动画以在动画完成后继续显示结束值(您可以在我的小作弊表中看到fillMode的可视化和其他与时序相关的属性).

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

这听起来很不错,但缺少Core Animation的一个重要部分:添加到图层的动画永远不会影响模型,只影响演示.该核心动画编程指南提到这部分"的第二页上的Core Animation基础知识 ":

图层对象的数据和状态信息与屏幕上该图层内容的可视化表示分离.

动画发生在一个名为表示层的单独图层上,这是您在屏幕上看到的.如果在动画期间打印出动画属性的值,则它们根本不会更改.

在动画期间,你在演示和模型之间有区别,但动画可能很短,一旦动画结束,差异就会消失,所以它并不重要......除非动画不会消失.然后差异持续存在,现在你必须处理两个地方的不同步数据.

怎么解决这个问题

可以说一切看起来都不错,只是命中测试是错误的.让补丁打到测试!更改命中测试以使用分段控件的图层表示层,命中测试将起作用.太棒了吧?这就像把一块石膏放在另一块上面而不是解决问题的根源.

如何摆脱副作用

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

当Apple在WWDC 2007上推出Core Animation时,他们使用这种技术来动画被删除的图层(例如淡出).以下引用来自会话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
Run Code Online (Sandbox Code Playgroud)