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...
Related
Is there a possibility that I can programatically say that only 1 UIView can be in landscape mode?
My Whole app has to be in portrait mode (not moving at all) but 1 UIView should be able to go in Landscape mode (To show pictures even better);
You rotate VC like this:
- (BOOL)shouldAutorotate {
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations {
return self.topViewController.supportedInterfaceOrientations;
}
Restrict VC so it won't rotate:
- (BOOL)shouldAutorotate { return NO; }
- (NSUInteger)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskPortrait);
}
You could change condition as per your need and this answer is referred from this link so you could go there for more understanding.
Also do keep that iOS 6/7 have different method for checking.If anything else then let me know.
UPDATED:- iOS 7 callBack method for checking mode
– willRotateToInterfaceOrientation:duration:
– willAnimateRotationToInterfaceOrientation:duration:
– didRotateFromInterfaceOrientation:
I've read almost every post around here regarding my problem but none of the solutions seems to work on my app.
So, I use a custom camera view (with buttons on toolbar and an overlay) that is being presented modally from a view controller. My app only supports landscape left and right for the orientation. And i want to stop the camera view from autorotating when it's being presented. I've put all the methods needed for autorotation on my view controller and my app delegate. I've checked on my plist file too and the supported rotations are correct. But my camera view keeps on rotating to any rotation (portrait and landscape) when I rotate the device, resulting on the overlay and the toolbar being incorrectly positioned. I also can't check on the camera view's orientation because i tried putting NSLog on shouldAutoRotate method, but it doesn't get called at all.
So how can I check the rotation on my custom camera view? And how can I force it to not rotate and stay still?
If my code is needed, I'll post it here. If anyone can help me on it I'll greatly appreciate it because it frustrates me so much right now.
Thank you. Cheers.
Create a new class of "UIImagePickerController" and implement the rotation delegates in the .m file as given,
// For lower iOS versions
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || ((toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)));
}
// For iOS version 6.0 and above
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskLandscape);
}
And make an instance of lets say MyImagePickerController instead of UIImagePickerController, and present it. This will work :)
Create a category for UINavigationController
#interface UINavigationController(autoRotation)
-(BOOL)shouldAutoRotate;
#end
#implementation UINavigationController
-(BOOL)shouldAutoRotate{
return [[self.viewControllers lastobject] shouldAutoRoatate];
}
-(NSUInteger)supportedInterfaceOrientations {
return [[self.viewControllers lastobject] supportedInterfaceOrientations];
}
#end
Implement these two methods in your corresponding view controllers
and return the orientation what u exactly want....
xcode -> file -> new file select cocotouch in the leftpane select objective-c category ->next
select give name Picker category on UIImageImagePickerController from dropdown
import
#interface UIImagePickerController (picker)
-(BOOL)shouldAutoRotate;
-(NSUInteger)supportedInterfaceOrientations;
#end
import "UIImagePickerController+picker.h"
#implementation UIImagePickerController (picker)
-(BOOL)shouldAutoRotate{
return yourOrientation;
}
-(NSUInteger)supportedInterfaceOrientations {
return yourInteger;
}
#end
After this when your device's orientation changed then the method shouldAutoRotate get called from your UINavigationController category at this time you have to find out if cameraview is presented if yes then you have to call shouldAutoRotate of Picker
See the following code
in your view controller's shouldAutoRotate
-(BOOL)shouldAutoRotate{
if([self presentingViewController])// Camera is present
return [instanceOfUIImagePickerController shouldAutoRotate];
return yourOrientaionNeededForThisVC;
}
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 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.
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; }