更改正在进行的动画

时间:2011-03-18 08:40:48

标签: iphone objective-c xcode ios core-animation

基本上,我想要做的是为云制作动画,然后在风改变时改变动画中的速度和/或方向。如果重要的是,我从UIViewController控制整个事情,云存在一个UIView,其上面有一个CALayer,这就是云本身。我也尝试过UIImageView。

对于TL:DR类型,简而言之,我要做的是获取动画视图的位置,或使用块动画停止动画视图。

这是完整的故事。我的问题是在动画期间获得它的位置。我正在使用块动画。因为我只知道它应该移动的速度,我需要通过使用距离来计算自己的时间。我尝试了以下代码,以及它的几个变体:

[[Cloud CloudImage]convertPoint:CGPointMake([[[Cloud CloudImage] presentationLayer] position].x, 0) toLayer:self.layer].x

Cloud是UIView,CloudImage是CALayer。这是我尝试过的最复杂的变化,我尝试了各种更简单的变体(例如,直接询问云,或者使用UIView而不是CALayer)。但是,它返回的只是它的最终值。我读了一些关于这个方法从3.2中被破坏的东西,但在4.2中被修复了;但是,当我将部署目标更改为iOS 4.3而不是4.0时,它没有修复。我使用的是4.3 base sdk。

我考虑的一些其他变化是暂时停止动画片刻,然后立即获得位置并开始新动画。但是,我需要知道一种方法来阻止基于块的动画,我只找到旧动画系统的片段(commitanimations)。

我考虑的最后一个是编写我自己的动画系统;云将在0.08秒左右重复NSTimer,并在每次触发时创建0.08秒的核心动画,为此它使用给予云的速度作为属性。但是,我担心这种情况的任何变化都会有更低的性能,而我需要尽可能轻量级,因为我同时拥有多达20个这样的云(有时也会下雨)。

提前致谢!

1 个答案:

答案 0 :(得分:7)

在这种情况下,我肯定会推出自己的系统,使用CADisplayLink而不是NSTimerCADisplayLink直接绑定,可以最大限度地减少使用内置动画代码的性能损失到屏幕更新计时器)。

你同时拥有20个云的事实并没有真正改变太多事情,因为我认为你的意图是使用内置的动画分别为这20个云设置动画。

如果你不确定它最终会对性能有多大影响,你可以尝试使用内置动画添加一堆云(大约50个),看看它们移动的速度有多慢,然后将其切换为内置动画代码并进行比较。

编辑:关于Stack Overflow的讨论会详细介绍如何做你要问的事情,以防你走这条路:Cancel a UIView animation?

示例:

// startAnimating called once to initiate animation loop. might be stopped e.g. 
// if game is paused or such
- (void)startAnimating
{
    // displayLink = the CADisplayLink for the current animation, if any.
    if (displayLink) {
        [displayLink invalidate]; 
        [displayLink release];
    }

    displayLink = [[CADisplayLink displayLinkWithTarget:self
                                               selector:@selector(animationTick:)] 
                   retain];

    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

// tick method is called at every interval; we want to update things based on 
// a delta time (duration), so that if things get bogged down and the updates 
// come less often, we don't go into slow motion
- (void)tick:(CADisplayLink *)sender
{
    CFTimeInterval duration = sender.duration;
    // here, we update the position for all the UIView objects. example:
    CGRect cloudFrame;
    for (UIView *cloud in clouds) {
        cloudFrame = cloud.frame;
        cloudFrame.origin.x += windForceX * duration;
        cloudFrame.origin.y += windForceY * duration;
        cloud.frame = cloudFrame;
    }
    // here we might update the windForceX and Y values or this might happen somewhere
    // else
}