Skip to content

Instantly share code, notes, and snippets.

@iccir
Last active May 31, 2019 03:44
Show Gist options
  • Save iccir/0bc3e9a751c13cbcb8ef to your computer and use it in GitHub Desktop.
Save iccir/0bc3e9a751c13cbcb8ef to your computer and use it in GitHub Desktop.
How to push a portrait-only UIViewController onto a landscape UINavigationController
// How to push a portrait-only UIViewController onto a landscape UINavigationController
- (void) _presentForcedVerticalNormalViewController:(UIViewController *)viewController animated:(BOOL)animated
{
UIView *(^makeSnapshotOfViewController)(UIViewController *) = ^(UIViewController *vc) {
UIView *result = [[vc view] snapshotViewAfterScreenUpdates:NO];
[[_rootViewController view] addSubview:result];
[result setFrame:[[vc view] bounds]];
[result setUserInteractionEnabled:NO];
return result;
};
// Manipulating the view controller hierarchy in completion blocks is dangerous and results in
// exceptions. This postpones the block for one cycle.
//
void (^then)(dispatch_block_t) = ^(dispatch_block_t block) {
dispatch_async(dispatch_get_main_queue(), block);
};
NavigationController *fakeNavigationController = [[NavigationController alloc] initWithNavigationBarClass:[NavigationBar class] toolbarClass:nil];
[fakeNavigationController setViewControllers:@[ viewController ]];
[fakeNavigationController setDelegate:self];
// As soon as we present fakeNavigationController, UIKit will attempt to redraw the ToC vc
// in landscape orientation. This looks bad, snapshot1 hides the glitch
//
UIView *snapshot1 = makeSnapshotOfViewController(_rootViewController);
[_rootViewController presentViewController:fakeNavigationController animated:YES completion:^{
[UIViewController attemptRotationToDeviceOrientation];
[snapshot1 removeFromSuperview];
then(^{
// snapshot2 prevents the ToC vc from showing up while we are dismissing the modal
// fakeNavigationController and pushing the original viewController
//
UIView *snapshot2 = makeSnapshotOfViewController(fakeNavigationController);
[_rootViewController dismissViewControllerAnimated:NO completion:^{
then(^{
[_rootViewController pushViewController:viewController animated:NO];
then(^{
[UIView animateWithDuration:0.1 animations:^{
[snapshot2 setAlpha:0.0];
} completion:^(BOOL finished) {
[snapshot2 removeFromSuperview];
}];
});
});
}];
});
}];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment