I am using UIImagePickerController to select a single image from photo library. There is a strange issue on iPad when it is in landscape mode.
The image picker is presented using UIPopoverPresentationController on iPad as recommended. When it is first presented, the status bar is correct:
However, when going into the second level of the photo library, the status bar is changed to portrait mode:
What I have noticed so far are:
This issue only appears in iOS 11, not iOS 10.
When it happens, rotate the iPad to portrait and back to landscape will fix the status bar orientation.
It only happened the first time presenting the picker controller.
If ignore, presenting other modal view will be in portrait mode:
The code that presenting the uiimagepickerController is as follow:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.modalPresentationStyle = UIModalPresentationPopover;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
[self presentViewController:picker animated:YES completion:nil];
UIPopoverPresentationController *popupController = picker.popoverPresentationController;
if (popupController) {
popupController.barButtonItem = sender;
}
Any idea what have I done wrong, or it is a bug?
Whole example project can be downloaded here:
https://www.dropbox.com/s/zgipclyr0mz26c6/test.zip?dl=0
I have finally found the cause of my issue.
My app needs to support all orientation on iPad and Portrait mode only on iPhone. Therefore I added the following code of UIApplicationDelegate:
- (UIInterfaceOrientationMask) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if (window.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
But sometimes it gives me nil window, as in the case of UIImagePickerController presented using UIPopoverPresentationController on iPad, and will return UIInterfaceOrientationMaskPortrait and cause the status bar rotates to portrait mode. I have also noticed that this happens only when UIRequiresFullScreen is checked.
I have solved my issue by checking that window is not nil as below:
- (UIInterfaceOrientationMask) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if (window) {
if (window.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
} else {
return UIInterfaceOrientationMaskPortrait;
}
} else {
return UIInterfaceOrientationMaskAll;
}
}
As I am working with iOS application support only Portrait Orientation.
But I am getting some Orientation related issue.
My app support only portrait orientation
when my parent P1.view is push using navigation it is in portrait mode thats fine. Now from P1.view I am subviewing my child view C1.view
Now I am in childview C1.view and from there using delegate I am calling
-(void)imagePickerController:(UIImagePickerController *)picker
[self.delegate openCamera];//called from C1.view
-(void)openCamera //declared in P1.view
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;>
[self presentModalViewController:picker animated:YES];
}
Now when I capture photo in Lanscape mode and dismiss that
presentModalViewController my view appears in Landscapmode instead of Portrait
mode.
- (BOOL)shouldAutorotate {
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
- (NSUInteger)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
}
This methods are define in both the view controller(P1 & C1) and also called when modelview dismiss, but my viewcontroller remains in Landscape which should not be happen.
This code working fine in iOS6 but not iOS7
I think that preferredInterfaceOrientationForPresentation is not supposed to return a bit mask. You could try:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
I have a view controller which I want to lock down in portrait mode. By creating a custom navigation controller I have been able to force portrait mode when the device is in landscape, and that works initially when the app starts up.
But when I rotate the device to portrait mode and then back to landscape, the orientation changes again.
I would assume that shouldAutorotate returning NO should prevent this, but it doesn't for some reason. I verified that function is being called every time I physically rotate the device.
Anyone know why iOS is ignoring my shouldAutotate of NO?
I've read many posts on this and my code seems to be what many people are suggesting, but doesn't work.
#interface MyUINavigationController : UINavigationController
#end
#implementation MyUINavigationController
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait ;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
NSLog(#"shouldAutorotate called and returning NO");
return NO;
}
#end
// This is how I am using my custom Navigation Controller:
UINavigationController* mynav = [[MyUINavigationController alloc] initWithRootViewController:customViewController];
visibleVC = [[[UIApplication sharedApplication] keyWindow] rootViewController];
[mynav setModalPresentationStyle:UIModalPresentationFullScreen];
[mynav setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[visibleVC presentViewController:mynav animated:YES completion:nil];
I am creating an app which is in landscape mode and I am using UIImagePickerController to take photos using iPhone camera in it and I want to create it in landscape mode too.
But as the Apple documention suggests UIImagePickerController does not support landscape orientation, so what should I do to get desired functionality?
If you'd like to use UIImagePickerController in landscape mode, use user1673099's answer, but instead of:
- (BOOL)shouldAutorotate
{
return NO;
}
use:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
and then the picker would open in landscape mode:
But make sure you check Portrait in deployment info:
... and I want to create it in landscape mode too.
One line of code can make a big difference! In the method or function where your IBAction lands:
In Swift,
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
// .overCurrentContext allows for landscape and portrait mode
imagePickerController.modalPresentationStyle = .overCurrentContext
Objective-C,
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
[imagePickerController setDelegate:self];
[imagePickerController setModalPresentationStyle: UIModalPresentationOverCurrentContext];
Note: This will allow imagePickerController to present it's view correctly, but will may not fix the issue of rotation while it is presented.
Try this way....
As per Apple Document, ImagePicker Controller never Rotate in Landscape mode. You have to use in Portrait Mode only.
For disable Landscape mode only for ImagePicker Controller follow below code:
In your ViewController.m:
Make the SubClass(NonRotatingUIImagePickerController) of Image Picker Controller
#interface NonRotatingUIImagePickerController : UIImagePickerController
#end
#implementation NonRotatingUIImagePickerController
// Disable Landscape mode.
- (BOOL)shouldAutorotate
{
return NO;
}
#end
Use as follow
UIImagePickerController* picker = [[NonRotatingUIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
etc.... Just as Default ImagePicker Controller
This is working for me & Let me know if you have any Problem.
This works great with Swift 4.0 in iOS 10/11.
import UIKit
extension UIImagePickerController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
}
Just drop the extension somewhere in your project, no need to subclass anything for it to work.
If you do need to specify device types, you can add a check like this:
import UIKit
extension UIImagePickerController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIDevice.current.userInterfaceIdiom == .phone ? .portrait : .all
}
}
This will allow an iPad to freely rotate, but enforces portrait mode on a phone. Just make sure that your app is configured to support these in its info.plist, otherwise you may encounter crashes upon launching the picker.
Here's a version that supports rotation in all interface orientations:
/// Not fully supported by Apple, but works as of iOS 11.
class RotatableUIImagePickerController: UIImagePickerController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
}
This way if the user rotates her device, it'll update the picker controller to support the current orientation. Just instantiate as you normally would a UIImagePickerController.
If you only want to support a subset of orientations, you can return a different value.
The correct way to use UIImagePickerController in landscape mode without any hacks is to put it into a UIPopoverController
- (void)showPicker:(id)sender
{
UIButton *button = (UIButton *)sender;
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
_popover = [[UIPopoverController alloc] initWithContentViewController:picker];
[_popover presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
Modify above code method
- (NSUInteger)supportedInterfaceOrientations
{
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if(orientation == UIDeviceOrientationLandscapeRight || orientation == UIDeviceOrientationLandscapeLeft)
return UIInterfaceOrientationMaskLandscape;
else
return UIInterfaceOrientationMaskPortrait;
}
Accepted answer doesn't work for me. I had also to add modalPresentationStyle to UIImagePickerController to make it working.
UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
pickerController.modalPresentationStyle = UIModalPresentationCurrentContext; //this will allow the picker to be presented in landscape
pickerController.delegate = self;
pickerController.allowsEditing = YES;
pickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:pickerController animated:YES completion:nil];
And of course remember to put this in a controller that presents the picker:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape; //this will force landscape
}
But according to Apple's documentation this is not supported to present this picker in the landscape mode so be careful about it.
If you're looking for SwiftUI solution in conjunction with the things mentioned here check this out here. Ignoring the safe area for the UIImagePickerController representable resolved a lot of my issues.
Is there any easy way to manually set the orientation of an interface? I need to set the interface to portrait even though the device orientation might be in landscape during loading. Kinda want to stay away from CGAffineTransforms.
One method I know that works for me (and is a bit of a hack and can display one orientation before changing to the orientation you want) is:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
}
}
First, set your app and views to only support portrait, then use this category method taken from my refactoring library, es_ios_utils:
#interface UIViewController(ESUtils)
// Forces without using a private api.
-(void)forcePortrait;
#end
#implementation UIViewController(ESUtils)
-(void)forcePortrait
{
//force portrait orientation without private methods.
UIViewController *c = [[UIViewController alloc] init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];
}
#end
The view, dismissed before the frame completes, won't be displayed.
override this to control the orientation until loading...
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation