Last active
May 31, 2019 03:44
-
-
Save iccir/0bc3e9a751c13cbcb8ef to your computer and use it in GitHub Desktop.
How to push a portrait-only UIViewController onto a landscape UINavigationController
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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