追踪 Core Animation 动画

12

我有两个在屏幕上移动的圆形。这些圆形都是包含其他UIView的UIView。每个圆形外部区域是透明的。

我编写了一个函数来创建连接两个圆形的四边形形状的CGPath。我在一个跨越整个屏幕的透明CALayer中填充这个路径。由于该层位于两个圆形的后面,因此它看起来将它们连接在一起。

最后,使用核心动画(Core Animation)对两个UIView进行动画处理。在此动画期间,两个圆形的位置和大小均会改变。

到目前为止,我唯一取得成功的方法是使用NSTimer定期中断动画,然后基于圆形的presentationLayer的位置重新计算和绘制光线。但是,当动画加速时,四边形会滞后于圆形。

是否有更好的方式可以使用Core Animation来完成这项任务?还是应该避免使用Core Animation并使用NSTimer实现自己的动画?

2个回答

13

我遇到了类似的问题。我使用层(layer)代替视图(view)来进行动画。你可以尝试像这样做:

  1. 将每个元素绘制为一个 CALayer,并将它们作为子图层(sublayers)包含在容器 UIView 的层(layer)中。UIView 更容易进行动画,但是你将拥有更少的控制权。请注意,对于任何视图,你都可以使用 [view layer] 获取它的层(layer);
  2. 为你的四边形创建一个自定义子层。该层应具有你要为其动画的一个或多个属性。我们称此属性为 "customprop"。由于它是一个自定义层,你希望在每一帧(frame)动画上重绘。对于你计划进行动画处理的属性,你的自定义层类应返回 YES needsDisplayForKey:。这样你就能确保每一帧(frame)都会调用 -(void)drawInContext:(CGContextRef)theContext
  3. 将所有动画(圆和四边形)放在同一事务(transaction)中;

对于圆形,如果是图像,则可以使用 CALayers 并设置内容,这是标准方式:

layer.contents = [UIImage imageNamed:@"circle_image.png"].CGImage;

现在,针对四重层,子类化CALayer并以这种方式实现:

- (void)drawInContext:(CGContextRef)theContext{
  //Custom draw code here
}   
+ (BOOL)needsDisplayForKey:(NSString *)key{
   if ([key isEqualToString:@"customprop"])
      return YES;
    return [super needsDisplayForKey:key];
}   

交易将如下所示:

[CATransaction begin];
CABasicAnimation *theAnimation=[CABasicAnimation animationWithKeyPath:@"customprop"];

theAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1000, 1000)];
theAnimation.duration=1.0;
theAnimation.repeatCount=4;
theAnimation.autoreverses=YES;
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
theAnimation.delegate = self;
[lay addAnimation:theAnimation forKey:@"selecting"];

[CATransaction setValue:[NSNumber numberWithFloat:10.0f]
                     forKey:kCATransactionAnimationDuration];
circ1.position=CGPointMake(1000, 1000);
circ2.position=CGPointMake(1000, 1000);
[CATransaction commit];

现在所有的绘制操作将同时发生。确保您的drawInContext:实现快速,否则动画会出现滞后。

向UIView的图层添加每个子层后,请记得调用[layer setNeedsDisplay]。它不会自动调用。

我知道这有点复杂。然而,与使用NSTimer并在每次调用时重新绘制相比,产生的动画效果更好。


对于那些选择实现完全编程动画而不是使用自定义属性的人,有一个提示:不要使用NSTimer,因为它会很慢且占用CPU。对于任何与动画相关的内容,请使用CADisplayLink,它与屏幕刷新率同步,并由CoreAnimation内部使用。 - skozin

1
如果您需要查找图层的当前可见状态,则可以在相关的CALayer上调用-presentationLayer,这将为您提供一个近似于用于渲染的图层。请注意,我说的是近似值-不能保证完全准确。但是,对于您的目的来说,它可能已经足够好了。

正如我所提到的,我已经尝试使用presentationLayer,但它落后于圆圈。我需要一种更可靠的方法来同步多个组件的动画。 - titaniumdecoy
我能想到的唯一可靠的方法是与动画机制相结合。您可以研究使用CAShapeLayer并将其路径与圆形同步进行动画处理。 - Lily Ballard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接