I have a screen that supports Device Orientation.
Everything is working fine except for the fact that when I rotate the device upside down (home button at top), the rotation doesn't work (it's stuck on the last landscape settings).
I know of several places needed be updated to support this:
In the VC itself, I added the methods:
In the Project Target, I updated as follow:
In the Storyboard VC Scene, I updated as follow:
What am I missing here?
You also have to allow rotating to all orientations in every parent view controller of the current main view controller. For example, if your view controller is in navigation controller, try subclassing it and override the same methods as in your example.
Edit: As #JordanC mentioned, since iOS 7 you can implement UINavigationControllerDelegate method to return custom supported orientations:
- (UIInterfaceOrientationMask)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController
As #eGanges mentioned the key point could be to subclass your UITabBarController (and override supportedInterfaceOrientations) if that is your initial view controller, in that case this is the only controller you should subclass (and of course you should add all the supported interface orientations to your app Info.plist file UISupportedInterfaceOrientations key)
Have you tested on real device?
anyway try this:
- (NSUInteger)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
Related
I want to say in each view controller which orientation he supports and restrict it to them. This is what I tried:
Use a custom navigation controller like in one of my old posts, but that doesn't seem to work anymore. The solution is similar to iOS 6 - (BOOL)shouldAutorotate not getting called for navigation controllers pushed viewControllers
I also tried Setting Orientation in Xamarin iOS, but the app crashes on the RootViewController. I get a NullReferenceException here.
Furthermore I tried IOS 8 : Restricting orientation on a View Controller from the deleted blog from Shri Chakraborty (shrixamarin). Here the app also crashes if I use application:supportedInterfaceOrientationsForWindow:, because the RootViewController is null. The solution seems to be similar to How do I restrict orientation per view controller in iOS7 in a navigation controller hierarchy
None of the solutions seems to work. Or do I miss something important? How can I restrict the orientation that view controller A is landscape only, view controller B is portrait only and view controller C can be shown in all available orientations?
Overriding GetSupportedInterfaceOrientations() in your view controller should solve the problem:
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations () {
return UIInterfaceOrientationMask.LandscapeRight;
}
The orientations you return here will be intersected with the app's allowed orientations (project properties) or with what you allow in your app delegate. So be sure to specify all orientations there or the maximum set of orientations you want to support.
See here for documentation.
I am working on a landscape view for a currently existing application. I believe I have autoRotate, supported interface, etc set up correctly, I am actually reusing code that works with a much simpler app. However when the simulator is rotated into landscape mode, the correct view loads, but the status bar and view stay with the short edge of the iPad. I've attached a screenshot and code. Is the problem with a view controller higher up in the chain, or the appdelegate? I've traced the called controllers in the debugger and it appears they are dismissed once this page is loaded. I am fairly new-ish to obj-c so it is possible this is something simple I am missing, but I have checked all attributes for the .xib file and everything looks copasetic.
Some of the code:
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;// | UIInterfaceOrientationMaskPortraitUpsideDown;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return NO;
}![enter image description here][2]
-(void)orientationChanged{
UIInterfaceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
if ((interfaceOrientation==UIInterfaceOrientationPortrait)||(interfaceOrientation ==UIInterfaceOrientationPortraitUpsideDown)){
self.view = self.portraitView;
} else {
self.view = self.landscapeView;
}
}
EDITS - This problem occurs on both iOS 7.1 and 6.1 and this is the first time any screen in the app supports a landscape view. To clarify the views, the portrait and landscape views are separate Views in single .xib file. The file owner class is set to the correct view controller class, and the parent view controller, a sales screen, should not rotate. It does not have a landscape view, but even with its autoRotate methods set to return YES the subview does not orient correctly.
Like 0x7ffffffff already said you need to allow rotation in your shouldAutorotate functions. Also you need to set up the supported rotation directions in your project setup.
First go to your project's settings:
Next you need to select all the orientations you want to support:
Another that is very important: ONLY the root View Controller will receive rotation events. If you nest a View Controller inside a View Controller then that nested Controller will not receive those events unless you wire them up manually from the parent. That's why I usually don't nest ViewControllers but use ad-hoc NSObjects or UIView implementations for nested views.
Last but not least: make sure your device is not rotation-locked: http://www.iphonefaq.org/archives/972915
The problem was occurring because a subclass of the customerView was not receiving the rotation notification. After tracking that class down it was a matter of setting up the NSNotificationCenter for orientation changes and then allowing autoRotation and supprotedInterfaceOrientations.
Comrades,
I just would like to know, how to enable Landscape Orientation only on Specific screens? As of now, I selected Landscape Left and Right options in General Settings and enabled in Supported interface orientations (iPhone) in plist file for the device Orientation, but that impacts all the screens.
I have nearly 80 screens in my application, I need to support both Portrait and Landscape about 5 screens, rest of the screens should be shown only in Portrait mode.
Any help is greatly appreciated!
Thanks,
Ramesh
In General Settings (which just adjusts your plist), you need to select all possible supported orientations. Then, you need to limit them in your specific view controller. If you're using a NavBar or TabBar controller, you need add your limitation there.
From the UIViewController docs:
In iOS 6 and later, your app supports the interface orientations defined in your app’s Info.plist file. A view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations. Typically, the system calls this method only on the root view controller of the window or a view controller presented to fill the entire screen; child view controllers use the portion of the window provided for them by their parent view controller and no longer participate directly in decisions about what rotations are supported. The intersection of the app’s orientation mask and the view controller’s orientation mask is used to determine which orientations a view controller can be rotated into.
To make this simpler, I created a category on UINavigationController that looks at the top-most view controller to determine it's rotation abilities. That way, in my specific view controllers that needed rotating, I could override those same methods and add landscape support.
#implementation UINavigationController (AutoRotation)
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
#end
Are your screens inside a UINavigationController? If so, I've noticed not all viewControllers can decide what orientations they support.
I am working on app which is totally in Landscape mode. On one of the view, I need to open the camera(UIImagePickerController) with overlay view. But When I click the button to open camera it get crashed with this issue i.e. reason:
'Supported orientations has no common orientation with the
application, and shouldAutorotate is returning YES'
I also put this line in viewcontroller but no effect.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
Please give me some idea to make it working.
If you are using a UINavigationController as base view controller , that code snippet you provided simply doesn't work. Because you are adding that code to a UIViewController but it's already embeded in a UINavigationController.
To overcome this issue, you must create a subclass of UINavigationController and add that landscape related code to that subclass. Then assign this subclass to your Storyboard's base Navigation Controller. Then this issue will be solved.
This is your navigation controller sub class' .h file
#interface YourCustomNavigationController : UINavigationController
#end
And add this to your navigation controller subclass' .m file
- (BOOL)shouldAutorotate
{
//returns true if want to allow orientation change
return YES ;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
And make sure to assign this class to your base Navigation controller using interface builder's identity inspector.
Project settings,
EDIT:
You can present a UIImagePickerController in landscape mode. Regardless of what documentation says, you can actually subclass it and can override it's functionality to work on landscape mode. (atleast its working on iOS 7)
To do this, you must create a subclass of UIImagePickerController and add above lines to that subclass. Project settings must be same as screenshot (atleast one landscape mode and one portrait mode must be ticked).
Then use that subclassed ImagePicker controller when you presenting the camera. It would successfully load camera in landscape mode. But standard camera controls will be misaligned and messed up. So better to hide defaultControlls (picker.showsCameraControls = NO;) just like you've done and use an overlay view instead.
I am using SWRevealViewController (https://github.com/John-Lluch/SWRevealViewController) to handle switching between two controllers, a "front" and a "rear".
The front controller is a UINavigationController and the rear controller is just a plain UIViewController that displays a list of menu items. The front UINavigationController pushes an instance of a view controller named FrontViewController. The rear UIViewController is an instance of RearViewController. The instance of SWRevealViewController is set as the root view controller once it is configured with the front and rear controllers, the delegate property of the reveal controller is set to the app delegate itself.
In both FrontViewController and RearViewController I am overriding shouldAutorotate and returning NO as well as overriding supportedInterfaceOrientations and returning UIInterfaceOrientationMaskPortrait.
However the app auto rotates and goes into Landscape while these two views are displaying when I rotate the device.
supportedInterfaceOrientations seems to only be invoked in FrontViewController but the value is not honored and the device rotates into landscape orientation.
I can't simply set the entire app to Portrait either because I have other detail views that I do want to support Landscape (movie player, etc).
How can I get SWRevealViewController working so I can restrict the app to Portrait in certain child views of the controller?
I have also noticed that the presentation changes are not being honored as well. In RearViewController I am overriding prefersStatusBarHidden to return YES but this method is never invoked. Similarly in FrontViewController I am overriding preferredStatusBarStyle to return UIStatusBarStyleLightContent but this method is never called either.
I have UIViewControllerBasedStatusBarAppearance set to YES in my plist.
UPDATE:
I have tried to use PKRevealController as suggested in the comments but the behavior is exactly the same. Supported orientations and status bar styles are completely ignore. supportedInterfaceOrientations on FrontViewController is the only override invoked but the return value of UIInterfaceOrientationMaskPortrait is not honored.
UPDATE 2:
I'm thinking that this is simply a limitation of these controls and they pretty much expect the support orientations to be the same throughout the application. I did however try MFSideMenu (https://github.com/mikefrederick/MFSideMenu) and it seems to handle supported orientations in different child views exactly as you would expect it to. I still don't have the status bar visibility and styles working, unfortunately.
To achieve this while not avoiding SWRevealViewController: Inside of it there is implemented method supportedInterfaceOrientations, which needs to be edited. I have done this:
- (NSUInteger)supportedInterfaceOrientations
{
UINavigationController* frontNavigationController = (UINavigationController*)self.frontViewController;
if ([frontNavigationController.visibleViewController isKindOfClass:[VCgallery class]]) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown;
}
All my viewControllers are portrait only except those that are of class VCgallery, which can be both portrait and lanscape.
The solution ended up being to subclass PKRevealController and override supportedInterfaceOrientations, shouldAutorotate, preferredInterfaceOrientationForPresentation, prefersStatusBarHidden, and preferredStatusBarStyle.
While MFSideMenu did this for orientation it did not support status bar configurations. I also ran into a major bug with MFSideMenu that prevented me from using it in my project.
I made each method I override return a value from the appropriate controller depending on the circumstance. In the case orientation I return the value from self.frontViewController.topViewController (since I am using a UINavigation controller). Status bar style and visibility came from either self.frontViewController or self.leftViewController depending on the current state.
The same solution probably would have worked for SWRevealViewController as well but I preferred the API design of PKRevealController.
I figured subclassing would work from the beginning but I assumed that such a common scenario would be handled in the configuration of these controls.