iPhone 上的核心动画性能

Posted

技术标签:

【中文标题】iPhone 上的核心动画性能【英文标题】:Core Animation performance on iphone 【发布时间】:2009-10-19 11:59:25 【问题描述】:

我正在尝试在 iPhone 上使用 Core Animation 制作一些动画。我在 CALayer 上使用 CABasicAnimation。这是一个直接的动画,从屏幕顶部的随机位置以随机速度到屏幕底部,我有 30 个元素连续执行相同的动画,直到另一个动作发生。但动画开始时,iPhone 3G 的性能非常缓慢。图片只有8k。

这是正确的方法吗?我应该如何进行更改以使其表现更好。

// image cached somewhere else.
CGImageRef imageRef = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:@"png"]] CGImage];

- (void)animate:(NSTimer *)timer

    int startX          = round(radom() % 320);
    float speed         = 1 / round(random() % 100 + 2);

    CALayer *layer      = [CALayer layer];
    layer.name          = @"layer";
    layer.contents      = imageRef; // cached image
    layer.frame         = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));

    int width           = layer.frame.size.width;
    int height          = layer.frame.size.height;

    layer.frame         = CGRectMake(startX, self.view.frame.origin.y, width, height);

    [effectLayer addSublayer:layer];

    CGPoint start       = CGPointMake(startX, 0);
    CGPoint end         = CGPointMake(startX, self.view.frame.size.height);
    float repeatCount   = 1e100;

    CABasicAnimation *animation     = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.delegate              = self;
    animation.fromValue             = [NSValue valueWithCGPoint:start];
    animation.toValue               = [NSValue valueWithCGPoint:end];
    animation.duration              = speed;
    animation.repeatCount           = repeatCount;
    animation.autoreverses          = NO;
    animation.removedOnCompletion   = YES;
    animation.fillMode              = kCAFillModeForwards;

    [layer addAnimation:animation forKey:@"position"];

使用 NSTimer 触发动画。

animationTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(animate:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:animationTimer forMode:NSDefaultRunLoopMode];

【问题讨论】:

第 1 步:在 iPhone 3GS 上运行。 ;-) 哈哈。我做到了。效果很好。 但大多数 iphone 用户仍然使用 3G :) 【参考方案1】:

好的,这里有几件事:

为什么要使用 NSTimer 重复触发动画?只是让动画重复。如果他们需要暂停和重新同步,您可以使用键控动画来做到这一点。通过全部编程,您可以让渲染器运行,而无需频繁将新信息同步到渲染树中。

你正在做:

CGImageRef imageRef     = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:@"png"]] CGImage];

每个 0.2 秒触发一次的计时器上的 30 个对象?你有没有分析过你的应用程序?图像解码所花费的时间百分比是多少?如果您切换到使用 imageNamed:只要内存足够,iPhone OS 就会缓存图像,这应该会减少您的解码时间:

CGImageRef imageRef = [[UIImage imageNamed:[NSString stringWithFormat:@"%@.png", name]] CGImage];

另外,您的图像是否具有需要进行 Alpha 合成的透明度?如果您可以避免 alpha,那么在旧款 iPhone 上将获得巨大的速度优势。

【讨论】:

我正在使用 NSTimer 以 0.2 的间隔创建 30 个不同的动画。不同,我的意思是不同的位置和速度。实际上我在调用 animate: 之前已经缓存了 imageRef。我在那里剪切/粘贴代码,但缓存的图像有所帮助,但动画仍然非常缓慢。您正在使用 imageNamed,据我所知,使用 imageWithContentsOfFile 会更好,对吧?图像确实包含透明度。图片是圆形的,所以没办法。 我正在考虑改用关键帧动画,这会提高性能吗?我确实需要暂停动画并重新开始。如何在具有不同开始和结束位置的关键帧动画中实现它,并让渲染器完成工作? 好吧,如果你只是踢 30 种不同的动画,那么计时器似乎是不错的选择。至于缓存的事情,很高兴听到您已经在这样做,但是当您发布的内容和正在做的事情之间存在实质性差异时,可能会更难提供建议。鉴于你所说的,我怀疑关键帧是否会有这么大的帮助。有一点,从性能的角度来看,完全透明和 alpha 合成透明之间存在很大差异。鉴于您发布的内容,我不知道是否还有更多没有实际痕迹的人可以说。 啊,对。图像确实具有 alpha 透明度。我会尝试制作一些新的并尝试一下。我拥有的代码有点不同,因为我已经将创建 CALayer 和 CABasicAnimation 放在单独的方法中,但它与我在这里粘贴的代码基本相同。我会尝试将它们作为关键帧动画。【参考方案2】:

以我的经验 layer.contents = imageRef; // 缓存的图像是这个方法中最昂贵的调用。

出于测试目的,我会在它们上使用相同的图像对象。第一个可能会很慢,但其余的会很顺利。

据我了解,这是因为 UIImage 对象即使在创建后实际上也会从文件中提取所有数据,直到将其绘制在屏幕上。

那里有几篇文章表明,使用 nsurlconnections 通过 file:// 协议下载图像实际上将线程获取文件(无需编写任何线程代码),并且因为您是动画层而不是 uiviews,它真的将是异步的。

【讨论】:

以上是关于iPhone 上的核心动画性能的主要内容,如果未能解决你的问题,请参考以下文章

iPhone 动画核心图形

iOS核心动画高级技巧 - 8

使用 CAAnimationGroup 对两个核心动画进行分组会导致一个 CABasicAnimation 无法运行

使用核心动画层动画视图

iOS核心动画Core Animation

Core Animation 文档翻译 (第八篇)—提高动画的性能