How to autorotate UIView based on device orientation iOS 6? - ios

I have started my project with iOS 5.0, Now updated to iOS 6, I am facing problem in doing orientation, To test I have created a sample application, and added the following code in delegate...
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
And in my view controller I have implemented the following methods...
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
-(BOOL)shouldAutorotate
{
return YES;
}
All the above I have done after googled about iOS 6.0,when I load application, based on the option given in supportedInterfaceOrientations view is loading that is fine, now when I changes my device orientations... view is not changing accordingly at run time, how do I change my view based on the device orientation?
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[notificationCenter addObserver:self
selector:#selector(deviceOrientationDidChange)
name:UIDeviceOrientationDidChangeNotification object:nil];
Do I need to add observer like above and changes it programmatically? or Will the view change automatically by detecting device orientation?

try this
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
- (BOOL) shouldAutorotate {
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscape;
}
The previous code should work on iOS6
Anyways, I use this code on one of my projects. I have a boolean _firstTime, and I set it to YES before showing the viewController, then I change it to NO after the viewController appears
- (NSUInteger)supportedInterfaceOrientations {
if (_firstTime) {
return UIInterfaceOrientationMaskLandscape;
} else {
return UIInterfaceOrientationMaskAll;
}
}
- (BOOL) shouldAutorotate {
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (_firstTime) {
return return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft)||(interfaceOrientation == UIInterfaceOrientationLandscapeRight);
} else {
return YES;
}
}

Change in these method:
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
Note : No need to add observer for device notification.Given below method will specify orientation status
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
EDIT : Provide all your views will automasking according to requirement
EDIT : If using UINavigation Controller then its child View Controller's supportedInterfaceOrientations and shouldAutorotate method will not be called.
Refer this link.

Problem is with my iPad. it has a button to restrict auto rotation change... I was not aware initially, as I was worked fully with iPod.. Thanks all for your helps.

Related

iOS 7 programmatically change UI Orientation effectively

after browsing through stackoverflow for answers I decided to ask a question.
From my understanding, I'm supposed to override the supportedInterfaceOrientation to handle orientation. For example's sake I implemented it like this
- (NSUInteger)supportedInterfaceOrientations {
if (self.forceLandscape) {
return UIInterfaceOrientationMaskLandscape;
}
return UIInterfaceOrientationMaskPortrait;
}
This lets the controller start in landscape mode when presented and get the forceLandscape ON on default. Then there's a button that will change the orientation on button press
- (IBAction)buttonPress:(id)sender {
self.forceLandscape = !self.forceLandscape;
UIInterfaceOrientation o = UIInterfaceOrientationPortrait;
if (self.forceLandscape) {
o = UIInterfaceOrientationLandscape;
}
[UIApplication sharedApplication].statusBarOrientation = o;
}
Button press would alternatively change between portrait and landscape mode. By setting the status bar orientation it would call the supportedInterfaceOrientations to change the orientation for me. It does call the method and return mask portrait on first button press but it doesn't change the orientation for me. This is the issue I want to fix. Hope that there's a workaround for this.
Replacing the status bar orientation change to this code
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger: o] forKey:#"orientation"];
Does call supportedInterfaceMethod and it does change the orientation. However it only work once and that it has access to private code and will be rejected by Apple, which is not desirable.
Not sure that this solution works. In my project (iOS6,7), I fixe the orientation so I don't need to force to change the orientation. However, I found a function in UIViewController that "attemp to rotate the device orientation to the right one
-(BOOL)shouldAutorotate {
FLog(#"");
if (self.forceLandscape) { //force to landscape
return NO;
} else {
return YES; //let's application rotate it self
}
}
-(NSUInteger)supportedInterfaceOrientations {
if (self.forceLandscape) {
return UIInterfaceOrientationMaskLandscapeLeft;
} else {
//You can just allow Portrait.
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskPortrait;
}
}
// Notifies when rotation begins, reaches halfway point and ends.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
//save new orientation
_myOrientation = toInterfaceOrientation;
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
- (IBAction)buttonPress:(id)sender {
self.forceLandscape = !self.forceLandscape;
if (self.forceLandscape) {
_myOrientation = UIInterfaceOrientationMaskLandscapeLeft
} else {
//just do nothing
}
//call this to update orientation
[UIViewController attemptRotationToDeviceOrientation];
}

Lock a specific UIViewController in Landscape mode + Force landscape orientation

I have a specific UIViewController which I want to lock/force it orientation to Landscape only.
This is what I did so far, but without any success.... I'm trying to get this working for iOS 6 & 7.
What am I doing wrong?
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
// Return YES for supported orientations
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
if([AppConst isIPad]){
return UIInterfaceOrientationMaskLandscape;
}
return UIInterfaceOrientationMaskLandscape;
}
//not ios6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if([AppConst isIPad]){
return YES;
}
return interfaceOrientation == UIInterfaceOrientationLandscapeRight;
}
The method shouldAutorotateToInterfaceOrientation is deprecated in iOS 6. You want to use the method supportedInterfaceOrientations instead. If you also want to run on iOS 5 or earlier then you need to implement both methods.
You should also implement the method shouldAutorotate.
Just remove all those methods in your view controller and use this method
-(void)viewDidAppear:(BOOL)animated{
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationLandscapeLeft]
forKey:#"orientation"];}
Happy Coding

How to rotate view from portrait to landscape mode

I have a problem with orientations in my app. Assume that I have two views (with dedicated view controllers):
first should be displayed in portrait (it is displayed correctly)
second should be displayed in landscape (it is not displayed correctly)
It is coarctated and displayed in portrait (like in second image below).
When I rotate device horizontal and back to portrait everything is OK. But after pushing view it displays incorrectly (images below). How can I fix this?
I use CustomNavigationController whish inherits from UINavigatorControler and implements three methods:
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
return [self.topViewController shouldAutorotateToInterfaceOrientation:orientation];
}
In application delegate I initializing controller in this way:
self.navigationController = [[CustomNavigationController alloc] initWithRootViewController:self.viewController];
[self.window setRootViewController:self.navigationController];
First view controller implements orientation functions in this way:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if (orientation == UIInterfaceOrientationPortrait)
return YES;
return NO;
}
Second view controller implements orientation functions in this way:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if (orientation == UIInterfaceOrientationLandscapeRight)
return YES;
return NO;
}
hi declare a global variable BOOL isLandScape ;
initialize it as isLandScape=NO;
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if ((orientation == UIInterfaceOrientationLandscapeRight)||(orientation == UIInterfaceOrientationLandscapeLeft))
{
isLandScape=YES;
return YES;
}
else
{
isLandScape=NO;
return NO;
}
yourObject.frame=CGRectMake(isLandScape?0:0,isLandScape?0:0,isLandScape?1024:768,isLandScape?768:1024);
}
Check the question How to handle different orientations in iOS 6. See the answer there for a project example of exactly what you need.
Basically you need to embed a custom navigation controller in your viewcontroller (the one you want to rotate). Add the following method in this custom navigation controller (this if for landscape orientation but you can change to portrait too).
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
and add to your view controller that should rotate:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
Be sure Portrait, Landscape Right and Landscape Left orientations are enabled in your project. Then, if you want to block some orientations for a particular window:
– application:supportedInterfaceOrientationsForWindow:
To do this You can use this function:
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait];
You can use this wherever you want, but in application delegate (in didFinishLaunchingWithOptions) i must put this code:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
It's works perfectly!

ios7 interface orientation - restrict orientation to particular viewcontroller

I have two UIViewControllers in my UINavigationController stack, in which i need to support portrait and landscape orientations for the first viewController alone and for the second viewController, i need portrait support alone and not landscape.
In ViewController1, I have implemented the following methods,
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self changeFrames:toInterfaceOrientation]; //changing frames for orientation accordingly
}
and in ViewController2:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Also in project target, i have set to support all the 4 orientations.
Looking for any kind of help to solve the above issue.
Thanks in Advance.

Issue with presenting UIImagePickerController in iOS 7

My application runs in only landscape mode ! so I know UIImagePickerController presents only in portrait mode , so in iOS 6 , I had created a subclass of UIImagePickerController that forced UIImagePickerController to open in portrait mode:
#interface NonRotatingUIImagePickerController : UIImagePickerController
#end
#implementation NonRotatingUIImagePickerController
- (BOOL)shouldAutorotate {
return NO;
}
#end
//presenting picker controller :
UIImagePickerController *ipc = [[NonRotatingUIImagePickerController alloc]init];
ipc.delegate = self;
[self presentViewController:ipc animated:YES completion:nil];
This worked fine in iOS 6 , but now in iOS 7 my app does crash because of this :
2013-10-31 14:56:01.028 Medad[1731:60b] *** Terminating app due to
uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason:
'Supported orientations has no common orientation with the
application, and shouldAutorotate is returning YES'
This problem could be solved if I check Portrait in deployment info :
The problem is if I check this option my app does run in portrait too but I don't want it!
How can I solve this issue?
I have tested it and found that you should not handle the orientation via check box in target window as you shown in the above image because its your whole app orientation so please check all boxes to get all orientation supported. If you want some view in different orientations and some in different then you will have to handle it via coding in ViewController class by returning YES OR NO for orientation.
Here is my Sample. Which I made. Please check.
Below method will handle the orientation for ViewController
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
// Old Method
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
return NO;
}
else {
return YES;
}
}
So, Solution is: Make two custom class one for UIImagePickerController and another is for ViewController (For All ViewControllers) and just make them for specific orientation and use those class as super class of your UIImagePickerController and all ViewControllers respectively.
There is one simple solution to avoid changing the supported orientations of your app, and make the UIImagePickerController work correctly: return UIInterfaceOrientationMaskAll only when the picker has to be presented.
You can do it simply subclassing UIApplication and using these two methods:
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
UIViewController *topController = window.rootViewController;
if ([self hasPicker:topController])
return UIInterfaceOrientationMaskAll;
return [super supportedInterfaceOrientationsForWindow:window];
}
-(BOOL)hasPicker:(UIViewController *)controller
{
BOOL hasPicker = NO;
NSLog(#"Check Controller: %#", controller);
if ([controller isKindOfClass:[UIImagePickerController class]])
return YES;
for (UIViewController *child in controller.childViewControllers) {
hasPicker = [self hasPicker:child];
if (hasPicker)
return YES;
}
return NO;
}
In the first method, you are overriding the default supportedInterfaceOrientationsForWindows: method. Every time the method is called, you check all the view controllers in the hierarchy (through hasPicker:, a recursive method). If an UIImagePickerController is found, you return UIInterfaceOrientationMaskAll, otherwise you return the default setting of your app.
Another thing I suggest you: don't subclass UIImagePickerController, since Apple explicitly forbids it. Instead, use view controller containment as I did in this example:
Landscape Picker Example
NOTE: The example code works only with UIImagePickerController containment. If you subclass it and add it through presentViewController: you may have to adjust the behavior of the hasPicker: method. One other simple thing you can do: add an instance variable to your UIApplication subclass and set it when you show the picker, and unset when you dismiss
Another solution.
In every controller add, even to the controller that have the picker:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
|| interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
return YES;
}
return NO;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
Add this to your custom picker controller:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
return YES;
}
return NO;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
In every controller add:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft
|| interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
return YES;
}
return NO;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
For the controller you have the picker:
Design this view with only Portrait orientation. So, it will have the same orientation of the picker. This view will be the only view with Portrait orientation while the others with landscape.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
return YES;
}
return NO;
}
- (BOOL)shouldAutorotate {
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation==UIInterfaceOrientationPortrait) {
}
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
Other solutions will also crash in the views that have the picker since they don't return portrait orientation to handle the picker orientation. while not adding any code to this view controller will let this view to run in landscape and portrait.
So, my proposed solution that to run all the views in landscape and this one in portrait. having this view in portrait is more design logical to have the same orientation of the picker.
The following go into your custom picker:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
return YES;
}
return NO;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
You should also set in the subclass:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft ;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL)shouldAutorotate {
return YES;
}
Now you can remove from the settings "Portrait"
[EDIT]
Since the UIImagePickerController can only be presented in Portrait (as per Apple doc), is possible to do the other way around, enabling portrait and landscape orientation, but fixing the orientation in landscape of everything but the picker controller. I made a little sample downloadable from here.
Actually i had the same problem and solved it in a different way...
Actually this was identified as a bug in IOS6 happens with ImageViewController which only supports Portrait orientation ... so i spent lot of time and found a way around the same....
hope this helps so first things first...
add a property in your AppDelegate.h
#property BOOL model;
then in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.model=NO;
return YES;
}
also add this method in AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(!self.model)
return UIInterfaceOrientationMaskLandscape; //or needed orientation
else
return UIInterfaceOrientationMaskAllButUpsideDown;
}
then in your view controller before presenting the imagepicker
implement this code...
AppDelegate *appdelegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
appdelegate.model=YES;
and then you just change the value when you came back after picking image , ie, delegate method
AppDelegate *appdelegate=(AppDelegate*)[[UIApplication sharedApplication] delegate];
appdelegate.model=NO;

Resources