修改正在进行的动画

4
基本上,我正在尝试动画化一个云,并在风向改变时更改其速度和/或方向。如果有关系的话,我是从UIViewController控制整个过程的,云是一个UIView,其上有一个CALayer,即云本身。我还尝试了在其上放置UIImageView。

简而言之,我要做的就是获取动画视图的位置或使用块动画停止动画视图。

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

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

云是UIView,云图像是CALayer。这是我尝试的最复杂的变化之一,我尝试了各种较简单的方法(例如直接询问云,或使用UIView而不是CALayer)。但是,它只返回其最终值。我读到有关此方法从3.2开始出现问题,但在4.2中被修复;然而,当我将部署目标从4.0更改为iOS 4.3时,它并没有被修复。我正在使用4.3基础SDK。
我考虑过的其他几个变体是完全停止动画片刻,然后立即获取位置并启动新动画。但是,我需要知道如何停止块动画,并且我只找到了旧动画系统(commitanimations)的片段。
我最后考虑的是编写自己的类型的动画系统;云将在大约0.08秒的重复NSTimer下运行,并创建一个0.08秒的核心动画每次触发时,其中使用作为属性给出的速度给云。然而,我担心任何这种变化都会具有更低的性能,而我需要它尽可能轻巧,因为我最多同时有20个这些云(有时还带着雨)。
提前感谢!
1个回答

7
在这种情况下,我肯定会自己开发系统,并使用CADisplayLink而不是NSTimer来最小化性能损失(CADisplayLink直接与屏幕更新计时器相关联)。
事实上,您同时拥有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
}

很棒的答案,谢谢!之前从未听说过CADisplayLink,但它听起来正是我所需的。我担心有20朵云会使任何性能损失增加20倍的原因是。 - Erik S
我越想越确信自己制作动画系统要比使用现成的系统在性能方面更加出色,前提是你使用单个计时器同时更新所有云朵(而不是为每个云朵都设置一个计时器)。假设云朵移动方向相同之类的情况下,无论如何这也是你想要做的事情。 - Kalle
是的,这几乎就是我现在所做的!我只需要确保获得一个中央雨计时器,而不是每个云上都有一个,我没有意识到NSTimer会占用如此多的资源。唯一的区别是我将displaylink保存为实例变量,因为我只会启动它一次,并且一次只会有一个。这是一个坏习惯吗? - Erik S
不,我上面的代码也是这样做的。displayLink是一个实例变量。使用上述代码,如果您决定重新启动displayLink,就不会泄漏旧的displayLink(因此需要无效/释放部分)。 - Kalle
啊,没注意到你没有再次声明它。我也应该养成这个习惯,我想。 - Erik S
显示剩余3条评论

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