Is it possible for the UIViewController to present itself?

I have a UIViewController (lets call it Fred) that can be embedded in many different container types (UINavigationController, UITabBarController, or inside a modal). Fred has a button that, when pressed, should make Fred full screen.

Intuitively, this means that I would like to present Fred as a fullscreen modal, but there are two problems:

  • Fred is active in view hierarchy (vc cannot be active)
  • Fred had to introduce himself?

I tried to solve this problem by creating a full screen monitor that Fred can call like this:

[fullscreenContainer presentViewControllerAsFullscreen:self]

      

FullscreenContainerViewController implementation:

@property (nonatomic) UIViewController* proxyViewController

// Create a proxy VC to hold state of the original ViewController so that we can safely
// Remove it from it 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 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];
        }
    }];
}

      

It works, but it seems like it's possible. Maybe it will break in some subtle way? Is there a better approach to what I am trying to accomplish?

+3


source to share





All Articles