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

时间:2014-01-16 10:43:56

标签: ios objective-c core-animation cabasicanimation

在CABasicAnimation滑入和弹跳后,我无法找到让我的UI对象(UISegmentedControl)触摸响应的方法。我该怎么办呢?

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

动画示例GIF(循环播放):
enter image description here

代码我在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];

1 个答案:

答案 0 :(得分:30)

出了什么问题

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

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

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

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

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

  

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

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

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

如何解决此问题

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

如何摆脱副作用

这很简单:不要使用这些行并在完成后删除动画。有人可能会说这种技术(不是删除动画)已被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