I am making an iPad app that only supports landscape orientations, and in that app i am calling the photo Library using the following code
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType =
UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker.mediaTypes = [NSArray arrayWithObjects: (NSString *) kUTTypeImage, nil];
self.iPadPopoverController = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
[self.iPadPopoverController setDelegate:self];
[self.iPadPopoverController presentPopoverFromRect:CGRectMake(490, 638, 44, 44) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
However, This causes a crash with the following exception:
Uncaught exception: Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES
The Reason for the Crash:
After researching I found that the crash was due to the UIImagePickerController always being displayed in Portrait mode even when the interface orientation is Landscape.
How I tried to solve it:
After reading the
iOS6 release notes and several questions previously posted; I found that the method from which the crash was originating was in the Application Delegate's
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
the obvious solution was to have it return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait
however, I want my app to support Landscape only! so my first solution was to add a Boolean flag to the App Delegate and set it to YES just before I call the UIImagePickerController and set back to NO after I dismiss it.
And it worked, but I was not happy with it, it felt like a messy solution. So instead I had the method check for its caller and if it were the function that initializes the UIImagePickerController then the method would return UIInterfaceOrientationMaskPortrait.
-(BOOL) iPadPopoverCallerFoundInStackSymbols{
NSArray *stackSymbols = [NSThread callStackSymbols];
for (NSString *sourceString in stackSymbols) {
if ([sourceString rangeOfString:#"[UIViewController(PhotoImport) importPhotoFromAlbum]"].location == NSNotFound) {
continue;
}else{
return YES;
}
}
return NO;
}
That solution worked on the simulator and on the device.
Here is the weird part
After submitting my app to the store, all my users were reporting that the app was crashing whenever they would access the photo library. I looked over the crash reports and found that the crash was occurring due to the exception mentioned above. I could not understand why this was happening.
So I submitted a TSI(Technical Support Incident) to apple about this issue. They replied that the stack symbols are not human readable after the app is archived and that is why my check would always fail.
They also suggested testing on devices by archiving the project first into a .ipa file and installing it through iTunes inorder to detect issues like this in the future.
That's Great but my problem still exists
Does anyone know how to solve this problem?
In info.plist declare all orientations as supported.
You no longer need method application:supportedInterfaceOrientationsForWindow:, so it can be deleted.
Subclass root view controller
Add following methods:
- (BOOL)shouldAutorotate {
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
return self.interfaceOrientation;
} else {
return UIInterfaceOrientationLandscapeRight;
}
}
If you present modal view controllers and don't want them to be rotated, then you need to add this code to their root controllers too.
Related
I am trying to print a txt file from within a iPad 8.x application. So, I have this code:
- (void)onOpenWith:(UIButton *)theButton path:(NSString *)path
{
NSURL *URL = [NSURL fileURLWithPath:path];
if (URL) {
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:URL];
self.documentInteractionController.delegate = self;
[self.documentInteractionController presentPreviewAnimated:YES];
}
}
#pragma mark - UIDocumentInteractionControllerDelegate
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
{
return self;
}
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller
{
return self.view;
}
- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller
{
return self.view.frame;
}
Now everything is going as expected, I see a preview of the file, then I touch the icon on the top right corner of the screen and I am able to share the document in those applications that can handle it. However, if I touch PRINT I get this error message:
Application tried to present inside popover with transition style
other than UIModalTransitionStyleCoverVertical
and the app crashes. Sure, i understand it, but to which viewcontroller should I apply this transition? I have no control on the popover showing the print dialog...
In iOS 7 (real iPad not simulator) everything works...
Can anybody help me?
Thanks
Fabio
I also came across this issue, and the solution was that I had to build and run my app with Xcode 6 installed.
On my older machine, I have Xcode 5.1.1, and when run from there, this same issue appeared, and some more issues from this view (like cannot dismiss mail controller when opened from the top right corner).
I am using ZBarSDK for QR Code scanning feature. I want to use this only in PORTRAIT mode only. As per the documentation I set it up with below code line:
_reader.supportedOrientationsMask = ZBarOrientationMask(UIInterfaceOrientationPortrait);
As expected it works well with iOS 5 but with the same code this view changes orientation for iOS 6 & 7. Is supportedOrientationsMask only works with < iOS 6? Is there any other way to force this ZBar reader camera view to work only in Portrait mode? Thanks in advance
Here more details with Code:
if(_reader) // first check `_reader` is created or not?
{
[_reader.readerView stop]; // then stop continue scanning stream of "self.ZBarReaderVC"
for(UIView *subViews in _reader.view.subviews) // remove all subviews
[subViews removeFromSuperview];
[_reader.view removeFromSuperview];
_reader.view = nil;
}
_reader = [ZBarReaderViewController new];
_reader.readerDelegate = self;
_reader.supportedOrientationsMask = ZBarOrientationMask(UIInterfaceOrientationPortrait);
ZBarImageScanner *scanner = _reader.scanner;
// EXAMPLE: disable rarely used I2/5 to improve performance
[scanner setSymbology: ZBAR_I25
config: ZBAR_CFG_ENABLE
to: 0];
[_reader.view setFrame:CGRectMake(0, _topbar.frame.size.height, self.view.bounds.size.width, self.view.bounds.size.height-_topbar.frame.size.height)];
_reader.cameraOverlayView = [self CommomOverlay];
_reader.showsZBarControls=NO;
// present and release the controller
[self presentModalViewController: _reader
animated: NO];
Let me know in case more details required.
Finally found the solution.
The problem was like this:
ZbarViewController *reader was presented from my current view controller and it's portrait support property was not working somehow.
_reader.supportedOrientationsMask = ZBarOrientationMask(UIInterfaceOrientationPortrait);
What i did to resolve this issue is I created TBZbarViewController the new class which was inheriting the ZbarViewController class and placed the below method.
-(BOOL)shouldAutorotate{
return NO;
}
Then I used the TBZbarViewController *reader to present from My controller which solved the issue and it's working in Portrait mode only as needed.
Thanks.
I did like this, and is working for all iOS versions :
Step 1 : Set your Device Orientation
Step 2 : Add this code into you implementation (.m) file.
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_6_0
- (BOOL) shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
#endif
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
I have a photo app that overlays custom button on camera image picker (for taking picture, turning on/off the flash, other usual stuff etc.)
I want the control interface to support portrait orientation only (I am talking about the control button/interface only, and not the actual captured image), which was working fine till iOS 6.
However, having upgraded to xCode version 5.0 and having upgraded my iPad 3 to iOS 7 (GM Seed, for iPad WiFi 3rd Generation), I find that the camera picker interface auto-rotates when orientation is changed. Surprisingly, I tested the same build on an iPhone 5 (upgraded to iOS 7), but the auto-rotation problem did not manifest itself.
[To be double sure, I tested the same piece of code in iOS 6 again, and the auto-rotation did not happen, neither in iPhone or iPad].
Just to demonstrate how I handle my image picker, here's a bit of code snippet:
UIImagePickerController *pickercustom = [[UIImagePickerController alloc] init];
pickercustom.sourceType = UIImagePickerControllerSourceTypeCamera;
pickercustom.showsCameraControls = NO;
pickercustom.wantsFullScreenLayout = YES;
pickercustom.navigationBarHidden=YES;
pickercustom.view.userInteractionEnabled=YES;
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
if (IPAD.userInterfaceIdiom == UIUserInterfaceIdiomPad)
{
pickercustom.delegate = self;
UIDevice *currentDevice = [UIDevice currentDevice];
while ([currentDevice isGeneratingDeviceOrientationNotifications])
[currentDevice endGeneratingDeviceOrientationNotifications];
[self presentViewController:pickercustom animated:YES completion:nil];
while ([currentDevice isGeneratingDeviceOrientationNotifications])
[currentDevice endGeneratingDeviceOrientationNotifications];
}
else
{
pickercustom.delegate = self;
[self presentViewController:pickercustom animated:YES completion:nil];
}
}
The 'endGeneratingDeviceOrientationNotifications' was added to stop the interface from rotating (which hitherto worked fine).
I also tried adding these three methods after reading this: UIImagePickerController in iOS 6 doesn't work properly
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
...but this was, perhaps, an iOS 6 specific solution. It didn't work in my case.
Please let me know if you could figure out the root cause. It would be great help.
You are close. When you want to support rotation but want that one viewController to not rotate, things get tricky:
The UIResponder chain REALLY wants the whole app to have the same rotation. Just simply overriding the rotation delegate methods in your single class will not work. (FYI, in your case, you will need to subclass UIImagePickerController in order to add those methods.) You need to implement these delegate methods in your root navigation controller (You'll need to have your own sub-class, again), and override them to query the top-most viewController for its desired rotation. Something like:
// Handles the should Auto Rotation for all view controllers
- (BOOL)shouldAutorotate {
if ([self.topViewController conformsToProtocol:#protocol(CustomRotation)]) {
return [self.topViewController shouldAutorotate];
}
// Auto rotate the screen by default.
return YES;
}
// Handles the supported Interface Orientations for all View Controllers by seeing if
// the top level viewController responds to Custom Rotation callbacks.
- (NSUInteger)supportedInterfaceOrientations {
if ([self.topViewController conformsToProtocol:#protocol(CustomRotation)]) {
return [self.topViewController supportedInterfaceOrientations];
}
// The default rotation for the application.
return UIInterfaceOrientationMaskAll;
}
You can't use respondsToSelector: in place of conformsToProtocol: because the selector method will always return YES for any class that derives from UIResponder (so like, everything), and you'll have to override the rotation delegates on each and every UIViewController in your project to make this work. Instead, you can create a blank protocol (CustomRotation). In your custom rotation class require that protocol and include the overridden rotation delegate methods like you have above, with the your desired restrictions.
Lastly make sure your supported interface orientations are set properly in xcode and/or in your Application: didFinishLaunchingWithOptions method.
As far as R&D done by me for the same topic,Imagepicker Camera in IOS7 iPad have default interface to change orientation to landscape .They have designed interface in such a way.We cannot forcefully lock the orientation of it.
If still willing to do you have to use custom ImagePicker use AVCam https://developer.apple.com/library/ios/samplecode/avcam/Introduction/Intro.html
and Custom image picker...
http://www.codza.com/custom-uiimagepickercontroller-camera-view
and forcefully lock there orientation...
I'm new to iOS development, and Im developing my first app. (so sorry if Im asking a newbie question)
My app is all in portrait orientation, except to the place where I'm using UIImagePickerController to take a picture to be used in the app, what I'm doing is:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage];
picker.allowsEditing = NO;
[self presentModalViewController:picker animated:YES];
As my app is in Portrait, I need to make something to the UIImagePickerController be in landscape only. if I try to use:
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
It seems that I can't use, because my Xcode identify as a error in this lines (probably because of Xcode the version, I'm not sure). And I'm not sure, but it seems that if I'm developing for iOS 5.1 I will need to implement something for iOS 6.0 too, is it correct?
Can someone help me to understand what is need to make this UIImagePickerController, and only this view controller in the app, work in Landscape orientation and works in iOS 5.1 and 6?
Regards
As per the UIImagePickerController Class Reference
Important: The UIImagePickerController class supports portrait mode only. This class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified, with one exception. You can assign a custom view to the cameraOverlayView property and use that view to present additional information or manage the interactions between the camera interface and your code.
So it looks like forcing landscape mode is unsupported and discouraged, unless you do so by replacing the default controls with a custom cameraOverlayView.
Create a class named "CUIImagePickerController" inherited from UIImagePickerController, override following methods, now use this class!
#interface CUIImagePickerController : UIImagePickerController
#end
#implementation CUIImagePickerController
- (BOOL)shouldAutorotate {
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient {
return (orient == UIInterfaceOrientationLandscapeLeft) | (orient == UIInterfaceOrientationLandscapeRight);
}
#end
Regards,
try implementing below methods:
- (BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
I seem to be having the opposite problem from this post:
Autorotate in iOS 6 has strange behaviour
When I submitted my paid app to Apple, XCode made me update to iOS 6 on my test devices. I used the GUI in XCode to set my app to display only in portrait mode on the iPhone and only in landscape mode on the iPad. This works great on my iOS 6 iPhone and iPad. In iOS 5, however, the iPad is allowing the app to rotate to portrait, displaying my buttons in a letterbox-like black area that shouldn't be there, and crashing repeatedly.
I am using a Navigation Controller and storyboards.
I know shouldAutorotateToInterfaceOrientation is deprecated in iOS 6, but figuring it should still be called in iOS 5, I tried this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if ((UIDeviceOrientationIsLandscape(UIDeviceOrientationLandscapeLeft))||(UIDeviceOrientationIsLandscape(UIDeviceOrientationLandscapeRight))) {
return YES;
}
else return NO;
}
else
{
if ((UIDeviceOrientationIsLandscape(UIDeviceOrientationPortrait))||(UIDeviceOrientationIsLandscape(UIDeviceOrientationPortraitUpsideDown))) {
return YES;
}
else return NO; }
// Return YES for supported orientations
}
The above code seems to have done nothing. I am putting it in each of my view controllers; it seems I should really be putting it in my navigation controller, but because I set that up graphically, I'm not sure how to do that. Do I have to subclass my navigation controller and do everything in code? There must be a way to use the storyboard settings for this!
(Note: I am not using AutoLayout and apparently can't because of some older components I am including my software that just plain don't like it.)
What might be causing this? I'd like to fix it before too many people buy the app and complain! Thanks in advance...
I think the code should be like this, where you use "interfaceOrientation", parameter passed into the method for your comparison:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if ((UIDeviceOrientationIsLandscape(interfaceOrientation))||(UIDeviceOrientationIsLandscape(interfaceOrientation))) {
return YES;
}
else return NO;
}
else
{
if ((UIDeviceOrientationIsLandscape(interfaceOrientation))||(UIDeviceOrientationIsLandscape(interfaceOrientation))) {
return YES;
}
else return NO; }