views:

26

answers:

3

Hi,

I'm using UIView animation blocks to animate CALayer properties (backgroundColor in this case) on multiple layers on the display at once.

All layers are opaque, and I'm animating everything in one block, essentially like this

[UIView beginAnimations:@"outer" context:nil];
float duration = .25;
float offset = 0.0;
for( NSArray *viewsInPass in viewQueue ) {
   for( UIView *innerView in viewInPass ) {
       [UIView beginAnimations:@"inner" context:nil];
       [UIView setAnimationDelay:offset];
       [UIView setAnimationDuration:duration];
       [innerView.layer setBackgroundColor:[newColor CGColog]];
       [UIView commitAnimations];
   }
   offset += duration;
}
[UIView commitAnimations];

Once this has 4-5 concurrent layers animating their background color it get very choppy and the device essentially starts missing its render rate entirely and just freezes to the end of the remaining animations. All views do not overlap and they are all opaque, and are generally about 20x20 pixels.

I was a little shocked at how non-performant this is, especially after reading so many gratifying things about Quartz 2D etc. I feel like I must be missing something fundamental here!

Help!

+2  A: 

Opaqueness in the views is the single biggest performance impact - if you can keep them from overlapping and entirely opaque through the whole rendering process (i.e. no transparency anywhere in that view sequence, including the background), you'll get slightly better perf.

I managed to get a single large animation up at ~30 fps (i.e. whole screen), but ran into memory limitations (original iPhone/iPod) that ultimately killed me beyond that. If you want more than about what you're getting there, you'll need go into OpenGL land - either through a gaming framework or directly. The overhead of the objective-C calls in that loop to enable changing the offset at the same time that you're cycling through images will ultimately kill you.

heckj
+1  A: 

Edit: [removed]

Since you have each animation start as the previous one ends, you could start each in an NSTimer or the delegate didFinish callback instead of queueing all the animations at once. That would put less demand on the animation system.

You should try to make sure that no views are queued with different colors at the same time.

drawnonward
Actually, this is incorrect. CAAnimation has a transaction model and transactions do nest, so it queues all the animations with different start times into the same animation transaction . Without doing it this way the performance is even worse due to all the animation scheduling overhead.I've tried doing each pass individually and letting each animation run in it's own transaction independently, and it's got all sorts of issues. NSTimers lead to animation phase mismatches due to minor scheduling jitter. animationsDidFinish ends up not helping except for an additional selector call.
groundhog
If your views are not interactive, would it make a difference to move to CALayers within a single view.
drawnonward
+1  A: 

It turns out the issue is that all you need to add some sort of epsilon between the offsets you start with. You end up with n*2 animating at the tail of each pass and the start of the next just for an instant. For some reason this makes the animation system barf even if it's just a processing slice they share.

Making it be

offset += duration * 1.05;

resolved the jerkiness between passes that clogged up the animations.

groundhog