I am currently developing an application that works with iOS 5 and iOS 6.
Most of my views are only on Portrait orientation except for 1.
RotationNavigationController : Main UINavigationController that overrides supportedInterfaceOrientation and shouldAutorotate.
PageViewController : Pushed in RotationNavigationController and is displayed in Portrait orientation only.
ImageViewController : Pushed after PageViewController. Is displayed with UIInterfaceOrientationMaskAllButUpsideDown.
Here's what I have in the ImageViewController's ViewDidLoad
- (void)viewDidLoad
{
// currentMask is the value returned by supportedInterfaceOrientation
[(RotationNavigationController*)self.navigationController setCurrentMask:UIInterfaceOrientationMaskAllButUpsideDown];
[(RotationNavigationController*)self.navigationController setShouldAutorotate:YES];
}
And when I popViewController from ImageViewController in landscape, I get back to PageViewController in landscape mode too whereas PageViewController only supports Portrait orientation.
Of course, I reset the mask in the ImageViewController's viewWillDisappear to Portrait.
Is there a way for PageViewController to remain in Portrait orientation ?
Thanks for the link emrys57. I found out the solution down there, and it was quite trivial in the end :
In RotationNavigationController, just add the following method :
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
Related
I am handling all the orientations in the appdelegate.m file. supportedInterfaceOrientationsForWindow returns UIInterfaceOrientationMaskLandscape for some of my view controllers and UIInterfaceOrientationMaskPortrait for one viewcontroller.
When I move from a landscape viewcontroller to the viewcontroller I want to portrait supportedInterfaceOrientationsForWindow returns UIInterfaceOrientationMaskPortrait but my view controller appears in landscape.
Please help me I've been stuck for a long time. Testing on iPhone 6, iOS 9.
Let's say view A is one of the landscape views of your app and B is the intended portrait view. Now, when the device is initially held in portrait on A and B is then accessed, the view doesn't change the orientation to portrait (since the device was already in portrait).
I'd suggest 'tell' system that B is initially in landscape while preparing the segue and then in your viewDidLoad for B's view controller, change the orientation to portrait.
This way, no matter what the previous view's orientation, B will always open in portrait when it loads.
Use the following code to change the orientation. In case you are using segue use this code in
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
The orientation here should be opposite of the desired orientation in the next view controller.
I am developing an application which is in portrait mode.
But I want one view controller should display in landscape as well as in portrait mode.
I tried the following code but it doesn't work (not called).
- (BOOL) shouldAutorotate
{
return NO;
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationMaskPortrait;
}
First, you need to set in your plist all the orientations your app supports, this can be done in the 'General' tab in the project under "Deployment Info", for example:
Then, you can use the method supportedInterfaceOrientations,
I assume you are presenting the view controller modally, so simply override it, on the presenting viewController, which need to be only in portrait use:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
and in your presented viewController, which should also supports landscape, use: (or whatever orientation mask you would like)
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
P.S - there is a different behavior for viewController that is presented modally and for a viewController that push in a navigationController stack:
modalViewController will call its own supportedInterfaceOrientations, and will support these orientations
pushedViewController will call its navigationController supportedInterfaceOrientations, and will support these orientation.
So, if you are presenting the viewController modally, you need to override its own supportedInterfaceOrientations, but if you push this viewController, you need to set some BOOL property in the navigationController, so it will know which orientations to supports.
I advise you to present this viewController modally, it's more natural to use modalViewController for different device orientations.
P.S #2: about shouldAutorotate: if it returns 'NO', than supportedInterfaceOrientations is not called, so return 'YES'. It only says, if to rotate automatically when the device rotates. if it returns 'NO', you need to explicit rotate the viewController.
Well I hope I helped and didn't write an answer that is completely not regarded to what you asked... :)
When presenting a modal with UIModalPresentationCustom, it ignores the orientation methods, and displays / rotates to whatever the presenting VC is configured to.
Example:
Presenting VC supports Landscape and Portrait.
Presented VC supports Portrait only (via preferredInterfaceOrientationForPresentation and supportedInterfaceOrientations.
When presenting it in landscape without UIModalPresentationCustom, it rotates the view back to portrait, then presents the VC accordingly. Unfortunately, because I need the presenting VC to stay visible below, I am forced to use UIModalPresentationCustom. And when that happens, the presenting VC is forced into landscape mode, creating a messed up UI and generating constraint issues. And even when presenting in portrait, it becomes allowed to rotate into landscape, ignoring that shouldAutorotate returns NO.
PS: I found a workaround on iOS 7 by adding this method to my App Delegate, but it doesn't fix it on iOS 8.
#implementation UIViewController (customModalFix)
- (BOOL)shouldAutorotate
{
if ([self.presentedViewController isKindOfClass:[IntroViewController class]]) {
return [self.presentedViewController shouldAutorotate];
}
return YES;
}
#end
EDIT: Implementing supportedInterfaceOrientations on the presenting VC doesn't help at all, since it is only called when the view is loaded, not when a VC is about to be presented over it. Still haven't found a solution to this problem.
Maybe I'm late. The point is, when using UIModalPresentationCustom, the presenting VC will not disappear, and the presented VC is not considered to be presented full-screen (even if it does take up the full screen). Thus, it's the presenting VC that is consulted for the supported interface orientations. So the solution can be like:
- (NSUInteger)supportedInterfaceOrientations
{
if (self.presentedViewController) {
return [self.presentedViewController supportedInterfaceOrientations];
}
return [super supportedInterfaceOrientations];
}
If you only use UIModalPresentationCustom to keep the presenting VC visible below, say you need a clear colored VC, my answer here may work for you too:
https://stackoverflow.com/a/29167837/46940801
I work on an app on iPad with iOS 7. The main UIView (viewA) of this app is by construction always landscape. Inside the main view there is another small UIView (viewB). Both are controlled by the same mainViewController, that has this method
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
Starting with iPad in landscape orientation, when I rotate the iPad in the portrait position, viewA and view B remains as they are. All right.
Now I want to make a change. To be precise, I want that, when iPad rotate from landscape to portrait, viewA remains as before, but viewB rotate automatically. How can I do? Have I to make a separate ViewController for viewB?
Thank you.
You need to extend/inherit the ViewController and override shouldAutorotateToInterfaceOrientation method to return the proper orientation for view B
Example ViewControllerB.h:
#interface ViewControllerB : ViewControllerA {
}
ViewControllerB.m:
#implementation ViewControllerB
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)interfaceOrientation {
return true;
}
#end
I have a UINavigationController with a first ViewController that is a UITabBarController, that should not be rotating...
Then pushed UIViewController should rotate...
So far I have subclassed the UINavigationController and implemented those method :
- (BOOL) shouldAutorotate {
return [self.visibleViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.visibleViewController supportedInterfaceOrientations];
}
So it is the child controller that choose if it should autorotate...
I have so far managed to block rotation for UITabBarController and allow rotation for the pushed UIViewController.
The Only thing is, if the UIViewController is in landscape mode, and when I pop it, the UITabBarController will be in Landscape mode too, until the phone is put on the portrait mode, it will come back to normal and not rotate anymore...
I would like that when I pop the Landscape UIViewController, that the UITabBarController is already on portrait mode.
This new iOS 6.0 UI rotation management seems to be a pain !
As you rightly say, the device has not been rotated, so the revealed view controller does not insist on rotating the orientation when the old view controller is popped. If that's the behavior you want, use a presented view controller instead.
You can force interface rotation by rotating the status bar, but only if supportedInterfaceOrientations returns 0.