2

I'm building a title sequence for our game, where each title is a roughly half-screen-sized retina image which I'm displaying using a UIImageView.

The title sequence has simple 3 stages as it gradually grows and fades in/out:

// 1. Fade in and grow
[UIView animateWithDuration:1.0f animations:^{
    titleImageView.alpha = 1.0f;
    titleImageView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
} completion:^(BOOL finished) {

    // 2. Stay opaque, grow a little more
    [UIView animateWithDuration:2.0f animations:^{
        titleImageView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
    } completion:^(BOOL finished) {

        // 3. Fade out, grow even further
        [UIView animateWithDuration:2.0f animations:^{
            titleImageView.alpha = 0.0f;
            titleImageView.transform = CGAffineTransformMakeScale(1.3f, 1.3f);
        } completion:nil];

    }];

}];

At the start of each animation stage, there's a stutter as a frame or two is dropped. It's especially noticeable on older hardware such as iPhone 4 and iPad 3, but it's even noticeable on an iPad Air, which is surprising.

Some deductions:

  • It's got nothing to do with the loading of the UIImage itself, because I've tried pre-loading the data and ensuring that the PNG has been decompressed. Also the stutter happens at every stage of the animation, even after it has been on screen for a while.
  • I used the Time Profiler instrument and noticed that CA seemed to be copying around PNG data in the background each time it stuttered, although I'm not sure why / what for. Surely the CALayers shouldn't need to re-create any image data on CPU each time the transform is changed?
  • EDIT: Also note that I tried it without animations (just setting those transform properties, also without alpha changes), and got the same results.

Also note that I have some OpenGL ES graphics going on in the background (it's a game with UIKit controls in the foreground), but that hasn't caused problems in the past...

Joseph Humfrey
  • 2,974
  • 2
  • 23
  • 34
  • 1
    UIImageView is responsible for its own child layer which holds the actual image. Maybe when you set the transform it is trying to rerender to look its best at the new scale. – Brian Nickel Jun 02 '14 at 15:57
  • Yeah, that sounds like a pretty reasonable explanation. Not sure what to do about it though! – Joseph Humfrey Jun 02 '14 at 16:01
  • Use Core Animation tool as described here: https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/MeasuringGraphicsPerformanceinYouriOSDevice/MeasuringGraphicsPerformanceinYouriOSDevice.html – matt Jun 02 '14 at 16:47

1 Answers1

2

So, it's slightly ugly, but I solved it with two approaches simultaneously:

  1. I converted the cascading UIView animations into a single CALayer keyframed animation so that they're continuous rather than stopping at each stage, calling the completion handler, and starting a new animation. Perhaps this stops them from "settling" and re-rendering in their new scale, as Brian Nickel pointed out.
  2. But this didn't prevent the very first stutter as it showed each new UIImage. To solve this, I created all UIImageViews (6 of them in total) up-front, added them to the superview, and set their alphas to zero. The images aren't huge, and there aren't too many of them, so this seemed okay.
Community
  • 1
  • 1
Joseph Humfrey
  • 2,974
  • 2
  • 23
  • 34
  • 1
    thank you Joseph. Your second trick, the adding of it the View and then changing transparency is a genius little trick to stop that redraw stutter! – Confused Sep 23 '14 at 14:02