I have a UIViewController (lets call it Fred) which may be embedded inside many different types of containers (UINavigationController, UITabBarController, or within a modal). Fred has a button that when tapped, needs to make Fred fullscreen.
Intuitively, this means I would like to present Fred as a fullscreen modal, but there are two problems:
- Fred is active in the view hierarchy (cannot present a vc that is active)
- Fred would need to present himself?
I tried to solve this by creating a fullscreenContainerViewController which Fred can call like this:
[fullscreenContainer presentViewControllerAsFullscreen:self]
Implementation of FullscreenContainerViewController:
@property (nonatomic) UIViewController* proxyViewController
// Create a proxy VC to hold state of the original ViewController so that we can safely
// Remove it from it's hierarchy and then restore it after fullscreen is dismissed.
- (void)presentViewControllerAsFullscreen:(UIViewController*)originalController
{
UIViewController* originalParentViewController = originalController.parentViewController;
UIView* originalSuperview = originalController.view.superview;
self.proxyViewController = [[UIViewController alloc] init];
self.proxyViewController.view = [[UIView alloc] initWithFrame:originalController.view.frame];
self.proxyViewController.view.autoresizingMask = originalController.view.autoresizingMask;
// Detach contentController from parent
[originalController willMoveToParentViewController:nil];
[originalController.view removeFromSuperview];
[originalController removeFromParentViewController];
// Put in the proxy view controller in place of the orignalController
[originalParentViewController addChildViewController:self.proxyViewController];
[originalSuperview addSubview:self.proxyViewController.view];
[self.proxyViewController didMoveToParentViewController:originalParentViewController];
originalController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.proxyViewController presentViewController:originalController animated:YES completion:nil];
}
And then to dismiss:
- (void)dismissFullscreenWithCompletionHandler:(void (^)(void))completionHandler
{
UIViewController* parentToRestoreTo = self.proxyViewController.parentViewController;
UIView* superviewToRestoreTo = self.proxyViewController.view.superview;
[self.proxyViewController dismissViewControllerAnimated:YES completion:^(void) {
// Detach proxy view/controller
[self.proxyViewController removeFromParentViewController];
[self.proxyViewController.view removeFromSuperview];
self.proxyViewController = nil;
// Restore original parent relationship
[parentToRestoreTo addChildViewController:self.contentController];
[superviewToRestoreTo addSubview:self.contentController.view];
[self.contentController didMoveToParentViewController:parentToRestoreTo];
if (self.shouldRestoreStatusBar) {
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationSlide];
}
}];
}
This works, but it seems anti pattern possibly? Maybe it will break in some subtle way? Is there a better approach to what I'm trying to accomplish?