Bob Spryn Bob Spryn - 23 days ago 9x
Objective-C Question

Animating a UIView frame, subview UIScrollView doesn't always animate

In this example.

I'm animating the PhotoViewerViewController's frame when I animate out the tabBarController (for fullscreen effect). The PhotoViewer uses a uiscrollview to generate the same sort of effect Apple's photos app does. For whatever reason sometimes it animates along with my PhotoViewer frame, and sometimes it doesn't.

You can see in the first example it jumps when increasing the frame size, but animates nicely when decreasing the frame size (and restoring the tab bar).

However in this example when the photo is vertical it jumps in both directions.

In both cases if I zoom in on the photo at all with the scrollview, it animates correctly in both directions.

I know the evidence is there, but I can't put my finger on what's happening here.

Here's my animation block:

void (^updateProperties) (void) = ^ {
self.navigationController.navigationBar.alpha = hidden ? 0.0f : 1.0f;
self.navigationController.toolbar.alpha = hidden ? 0.0f : 1.0f;
if (self.tabBarController) {

int height = self.tabBarController.tabBar.bounds.size.height;
for(UIView *view in self.tabBarController.view.subviews)
int newHeight;
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsPortrait(orientation)) {
newHeight = hidden ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.height - height;
} else {
newHeight = hidden ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.width - height;

if([view isKindOfClass:[UITabBar class]])
[view setFrame:CGRectMake(view.frame.origin.x, newHeight, view.frame.size.width, view.frame.size.height)];
CGRect newFrame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, newHeight);
[view setFrame:newFrame];

// update our VC frame with animation
[self.view setFrame:newFrame];




Code adapted from a post on SO: UITabBar wont hide

Full source on github.


In general, if animations sometimes work and sometimes don't, it's because in the latter case a delayed perform is causing them to be effectively cancelled by setting the property concerned to its final value.

In the particular case of UIScrollView it often happens that -layoutSubviews is called without animation one run loop after your animation blocks have closed. For this reason I usually try to avoid doing any layout in that method where I have a UIScrollView in the view hierarchy (because particularly prior to iOS 5, UIScrollView is really trigger-happy on setting itself to need layout).

I would recommend removing your call to -[EGOPhotoImageView layoutScrollViewAnimated:] from -layoutSubviews and add it to an overridden -setFrame: instead.

If you can target iOS4 and above, take a look at UIViewAnimationOptionLayoutSubviews too. Using a block-based animation with this as an option might just work without changing anything else.