Archive for December 29th, 2008

29
Dec

Snippet: Full screen presentModalViewController

Today we have a little iPhone user interface programming problem to present to you with its not so self evident solution, courtesy of the kind assistance of one Bryan Henry on the iphonesdk list.

The scenario is, we’ve pushed a pack of controllers onto our UINavigationController as we drill down through the interface, and now we’ve reached a place where the user taps something that we want to enter a full screen display state for momentarily. Well, that’s easy enough, the naïve iPhone programmer thinks to himself, we’ll just hide the status bar then modally present a controller with a full screen view, right?

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];

FullscreenController *fullscreenController = [[FullscreenController alloc] initWithNibName:@”Fullscreen” bundle:nil];

[self.navigationController presentModalViewController:fullscreenController animated:NO];

[fullscreenController release];

Yes, he would think that. But he WOULD BE WRONG. What actually happens is that the view is presented below the empty space where the status bar used to be. Bah. Fooling with offsets in the “Fullscreen” xib file simply results in the view being clipped by that empty space. Double bah. Thankfully, a plaintive plea to the list produces in short order an explanation:
Your problem is that the UITransitionView that is used to animate in   
your modal view has clipsToBounds=YES, so any drawing that should   
happen in the rect where the status bar would be doesn’t happen since   
the UITransitionView’s bounds don’t extend there. I ran into this just   
the other day. The (somewhat hackish but completely safe) solution was   
to set clipsToBounds=NO for the UITransitionView whenever its set as   
the superview (or rather, whenever your view is added as a subview of   
the UITransitionView). 
Well, that was somewhat less than intuitive, wasn’t it now? So what you need is a patched UIView class,

@interface NoClipModalView : UIView

}

@end 

@implementation NoClipModalView

- (void)didMoveToSuperview

   self.superview.clipsToBounds = NO

@end 

and then in your controller, rather than having it actually load the nib, you override -loadView to have it create one of those, and then create your fullscreen views inside it.

- (void)loadView

{

   // instead of calling [super loadView], which doesn’t account for a hidden status bar, create an unclipped view here

   CGSize screenSize = [UIScreen mainScreen].bounds.size;

   CGRect screenBounds = CGRectMake(0, -20, screenSize.width, screenSize.height);

   NoClipModalView *sView = [[NoClipModalView alloc] initWithFrame:screenBounds]; 

   self.view = sView; 

   [sView release];

   // and then manually create the view(s) you want inside it.

   TWGestureImageView *newImageView = [[[TWGestureImageView alloc] initWithFrame:screenBounds] autorelease];

   self.imageView = newImageView;

   [self.view addSubview:self.imageView];

}

 And that, dear friends, is how to create a full screen modal display. Reverse it from where you created the FullscreenController up at the top with the expected

   [self.navigationController dismissModalViewControllerAnimated:NO];

   [[UIApplication sharedApplication] setStatusBarHidden:NO animated:NO];

and th-th-that’s all folks!