Force landscape orientation in UIImagePickerController - ios

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;
}

Related

ZBarReaderViewController reader view changes orientation for iOS6 & iOS7 even after restricting it by _reader.supportedOrientationsMask

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);
}

UIImagePickerController not full screen

Since the iOS7 upgrade, I have a weird behaviour of the UIImagePickerController. In this application I am using the UIImagePickerController with a cameraOverlayView.
In iOS6 I called the UIImagePickerController using the following code:
_picker = [[UIImagePickerController alloc] init];
if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {
_picker.sourceType = UIImagePickerControllerSourceTypeCamera;
_picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
_picker.cameraDevice = UIImagePickerControllerCameraDeviceRear;
_picker.showsCameraControls = NO;
_picker.navigationBarHidden = NO;
_picker.toolbarHidden = YES;
_picker.wantsFullScreenLayout = YES;
_overlayViewController = [[OverlayViewController alloc] init];
_overlayViewController.picker = _picker;
_overlayViewController.frameSize = self.frameSize;
_overlayViewController.delegate = self;
_picker.cameraOverlayView = _overlayViewController.view;
}
else {
_picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
_picker.delegate = self;
Where the OverlayViewController is an UIViewController, with a transparent background which draws some custom controls on screen.
But now in iOS 7 the camera is drawn through the statusbar and a black bar appears beneath the live camera view.
I can solve this by applying a CGAffineTransformMakeTranslation to the cameraViewTransform property of the UIImagePickerController, but why is this like this?
In iOS 7, by default UIViewController views take up the entire screen area including the status bar.
wantsFullScreenLayout
is deprecated and ignored. In some cases, this fix works (in the view controller class):
if ([self respondsToSelector:#selector(setEdgesForExtendedLayout:)]) {
[self setEdgesForExtendedLayout:UIRectEdgeNone];
}
In other cases, it's a bit more complicated. It's late here, so see how you go with it. Helpful things to note - in a UIViewController, the following code will give the correct statusbar height on both iOS 6 and iOS 7, should it come to having to align things using CGRect math:
if (UIDeviceOrientationIsLandscape(self.interfaceOrientation)) {
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.width;
} else {
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
}
And then don't forget that in Interface Builder, there are the new "iOS 6 delta" adjustments that allow you to design for iOS 7 and then use offsets to correct for iOS 6.
Anyhow, let me know how you go.
My understanding of the issue, based on a few other SO threads and such, is that UIImagePickerController does not do what we'd expect in terms of managing the status bar via [UIViewController -prefersStatusBarHidden].
This means you either have to disable view controller status bar management entirely, via plist, or figure out a way to get UIImagePickerController to do what we want. On the assumption that you're not looking for the former, I can say I've had success in the latter by putting the picker in a wrapper controller that does what I want (but fall back to your previous code if you still need to detect/support iOS6):
#interface PickerContainer : UIViewController
#property ( nonatomic, weak ) UIImagePickerController* picker;
#end
#implementation PickerContainer
- (void) setPicker: (UIImagePickerController*) picker
{
[self addChildViewController: picker];
[picker didMoveToParentViewController: self];
self->_picker = picker;
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.picker.view.frame = self.view.bounds;
[self.view addSubview: self.picker.view];
}
// Will have no effect in ios6 -- see [-init] for that option
- (BOOL) prefersStatusBarHidden { return YES; }
- (id) init
{
if ( ! ( self = [super init] ) ) return nil;
if ( detectThatThisIsIos6() ) self.wantsFullScreenLayout = YES;
return self;
}
#end
This will work for you, scaled camera, you will have a black bar at the bottom but it will get overlayed by tool bar
https://stackoverflow.com/a/15803947

Camera Image Picker controls - Auto Rotation in iOS7

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...

Autorotation in iOS 6.1 for custom camera view

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;
}

Using UIImagePicker in iPad with Landscape only on iOS 6

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.

Resources