UIDeviceOrientation ipad - ios

I have the following code to fill a view according to the orientation. This always returns landscape.
- (void)setData:(BCPlaylist *)list {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown){
NSLog(#"portrait");
[self setPlaylist:list];
[self renderPlaylist];
[activity stopAnimating];
}else{
NSLog(#"landscape");
[self setPlaylist:list];
[self renderPlaylistOne];
[activity stopAnimating];
}
}
I change views correctly in - (void)animateRotation:(UIInterfaceOrientation)interfaceOrientation
duration:(NSTimeInterval)duration {
But that doesn't work when already in landscape or portrait when changing a playlist.

Instead of using [[UIDevice currentDevice] orientation] for checking orientation use statusbar orientation to get the exact orientation.
UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

To avoid a warning, use :
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

You'd always get landscape, because that's your default (from your if statement). If you walk through the debugger with a breakpoint there, you'll see that the orientation reported is that of Unknown.
In fact, your code is fine, but this is a limitation of the simulator. If you take the same code, using Device orientation and not Interface orientation, you'll get actual values if you use it on the physical device, which can be driven by the if-statement you have.

Related

How change orientations programmatically [duplicate]

This question already has answers here:
Force landscape mode in one ViewController using Swift
(20 answers)
Closed 1 year ago.
In iOS 5 we could change the device orientation programmatically like so:
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
But in iOS 6 setOrientation is deprecated, how may i change the device orientation programmatically in iOS 6?
Here are my "five cents", tested on iOS7 with ARC
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
This doesnt generate "leak" warning as performSelector will.
UIAlertView - with this code, when you open UIAlertView during view(will/Did)appear you will notice that all but this view is in portrait (apple, really?) I wasn't able to force the view to reorient but found that if you put slight delay before opening the UIAlertView then view has time to change orientation.
Note I'm releasing my app week commencing 12/09/2014 and I will update post if it will pass or fail.
I found out that the easiest way to force the device to change orientation is to present a new view controller (using presentViewController:animated:completion:) where the new view controller specified a particular preferred orientation (by implementing the method -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation).
When a new view controller is presented, as expected, the orientation will change to the one preferred by the new view controller. So, simplest implementation (best practice?) will be to embed all functionality you needed in a specific orientation into a separate view controller, and present it as needed. The system will take care of changing the orientation for you.
Obviously this might not suit all use cases, but, fortunately the same trick is applicable to force the device to change orientation for existing view controller.
The trick is to present a new view controller with the specific preferred orientation that you needed, and then hide it immediately. This will cause the orientation to change temporary when the new view controller is presented. The best part is, when the new view controller is dismissed, the original (presenting) view controller's preferredInterfaceOrientationForPresentation is queried again, you can specify the final orientation you want here.
One important thing to look out here is to also temporary disable auto rotation in the original view controller (when coming back from the newly presented-then-dismissed view controller), so that when user rotate their phone towards the new orientation, it does not triggered further auto rotation.
The following code should illustrate my point, my example forces rotation to portrait, just change accordingly if you want other orientation.
Assuming you have the original view controller named Original, and a temporary view controller named ForcePortrait
#interface Original : UIViewController
{
BOOL orientationToPortrait; //should set to NO by default
}
#end
#implementation Original
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation
{
if(orientationToPortrait)
{
//when we manually changed, show in Portrait
return UIInterfaceOrientationPortrait;
}
else
{
//before manual orientation change, we allow any orientation
return self.interfaceOrientation;
}
}
-(BOOL) shouldAutorotate
{
//we should 'lock' the rotation once we manually change it
return !orientationToPortrait;
}
-(void) changeOrientationToPortrait
{
//Sample method to change the orientation
//when called, will show (and hide) the temporary view
//Original.preferredInterfaceOrientationForPresentation will be called again after this method
//flag this to ensure that we tell system we prefer Portrait, whenever it asked again
orientationToPortrait = YES;
//presenting the following VC will cause the orientation to temporary change
//when the new VC is dismissed, system will ask what is our (Original) orientation preference again
ForcePortrait* forcePortrait = [[ForcePortrait alloc] init];
[self presentViewController:forcePortrait animated:NO completion:^{
[forcePortrait dismissViewControllerAnimated:NO completion:nil];
}];
}
#end
#interface ForcePortrait : UIViewController
#end
#implementation ForcePortrait
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
This does not answer how to change the device Orientation, but an additional information that might help you.
iOS 6 UI Interface Orientation - shouldAutorotateToInterfaceOrientation: Not Working
The method shouldAutorotateToInterfaceOrientation: is NOT supported in iOS 6. Its deprecated. Just in case if you are a newbie, who just stared working in cocoa, and wondering why is your view controller messed up in iOS 6 and perfect in iOS 5, just know that shouldAutorotateToInterfaceOrientation: is not supported anymore. Even though it may work well with Xcode 4 to 4.3 it will NOT work on Xcode 4.5.
Apple provides a new method to get this thing done, in a much cleaner fashion. You use supportedInterfaceOrientations instead. It returns all of the interface orientations that the view controller supports, a mask of interface orientation values.
UIInterfaceOrientationMask Enum:
These constants are mask bits for specifying a view controller’s supported interface orientations.
typedef enum {
UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
UIInterfaceOrientationMaskLandscape =
(UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
UIInterfaceOrientationMaskAll =
(UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
UIInterfaceOrientationMaskAllButUpsideDown =
(UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight),
} UIInterfaceOrientationMask;
Using shouldAutorotateToInterfaceOrientation: method:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscapeRight(toInterfaceOrientation);
}
Using supportedInterfaceOrientations method:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
These are the added methods to UIViewController regarding Orientation in iOS6
UIViewController preferredInterfaceOrientationForPresentation
UIViewController shouldAutorotate
UIViewController supportedInterfaceOrientations
Added methods to UIApplication regarding Orientation in iOS6
UIApplication supportedInterfaceOrientationsForWindow:
UIInterfaceOrientationMask
Try this:
#import <objc/message.h>
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation)){
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)])
{
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
You should place
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
in your AppDelegate didFinishLaunchingWithOptions Method.
Then, anywhere in your application you can get the current orientation with:
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
And test orientation with:
UIInterfaceOrientationIsPortrait(orientation)
UIInterfaceOrientationIsLandscape(orientation)
as, like
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
// code for landscape orientation
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
}
else if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
// code for Portrait orientation
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortraitUpsideDown];
// OR
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
This code is for iOS 8 or later
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
Try this...It worked out for me...
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview]; [window addSubview:view];
#implementation UINavigationController (autorotate)
-(NSUInteger)supportedInterfaceOrientations
{
//make the check for iphone/ipad here
if(IPHONE)
{
return UIInterfaceOrientationMaskPortrait;
}
else
{
return UIInterfaceOrientationMaskLandscape;
}
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return NO;
}
A little modification to Bissy's answer, if you want to avoid using Runtime Library:
if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)])
{
int orientationPortrait = UIInterfaceOrientationPortrait;
NSMethodSignature *sig = [[UIDevice currentDevice] methodSignatureForSelector:#selector(setOrientation:)];
NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];
[invo setTarget:[UIDevice currentDevice]];
[invo setSelector:#selector(setOrientation:)];
[invo setArgument:&orientationPortrait atIndex:2];
[invo invoke];
}
}
This works for iOS7, force autorotate to portrait.
//In your viewController.m
#import <objc/message.h>
// for autorotate viewController to portraid
- (void)viewWillAppear:(BOOL)animated {
UIInterfaceOrientation orientationStatusBar =[[UIApplication sharedApplication] statusBarOrientation];
switch (orientationStatusBar) {
case UIInterfaceOrientationPortrait:break;
case UIInterfaceOrientationLandscapeLeft:
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait);
break;
case UIInterfaceOrientationLandscapeRight:
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait);
break;
default:
break;
}
}
// this permit autorotate
- (BOOL) shouldAutorotate
{
// this lines permit rotate if viewController is not portrait
UIInterfaceOrientation orientationStatusBar =[[UIApplication sharedApplication] statusBarOrientation];
if (orientationStatusBar != UIInterfaceOrientationPortrait) {
return YES;
}
//this line not permit rotate is the viewController is portrait
return NO;
}
NOTE: I implemented this option in my app, but probably would get rejected by Apple (comment for Austin for edited 6 of Sergey K. in oct 2012).
Apple made changing the device orientation programmatically in ios6 quite difficult (on purpose mind you).
As far as I know the only way to accomplish what you're asking is to simulate the change of device orientation.
Using setTransform to rotate the UIView and re-applying its own frame gives the desired results.
[YourView setTransform:CGAffineTransformMakeRotation(1.57)];
[YourView setFrame:CGRectMake(0, 0, YourView.frame.size.width, YourView.frame.size.height)];
And when the device physical orientation changes we can undo the transformation.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[YourView setTransform:CGAffineTransformMakeRotation(0)];
[YourView setFrame:CGRectMake(0, 0, YourView.frame.size.width, YourView.frame.size.height)];
}
if (self.interfaceOrientation != UIInterfaceOrientationLandscapeRight) {
// http://stackoverflow.com/questions/181780/is-there-a-documented-way-to-set-the-iphone-orientation
// http://openradar.appspot.com/radar?id=697
// [[UIDevice currentDevice] setOrientation: UIInterfaceOrientationLandscapeRight]; // Using the following code to get around apple's static analysis...
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationLandscapeRight];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return interfaceOrientation == UIInterfaceOrientationPortrait
|| interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ;
}
This works for me on Xcode 6 & 5.
- (BOOL)shouldAutorotate {return YES;}
- (NSUInteger)supportedInterfaceOrientations {return (UIInterfaceOrientationMaskPortrait);}
Its interesting how others didn't run to problems after not setting it like this :
+ (void)setOrientation:(UIDeviceOrientation)orientation {
[UIDevice.currentDevice setValue:#(orientation) forKey:#"orientation"];
[UIViewController attemptRotationToDeviceOrientation];
[UIDevice.currentDevice setValue:#(UIDeviceOrientationUnknown) forKey:#"orientation"];
}
My requirement was to be able to force orientation and then again rotate to device natural orientation... there is UIDeviceOrientationDidChangeNotification that can get you de information to witch orientation to rotate device back but actually it will partly not work if you don't set to unknown immediately after you changed orientation in UIDevice, also there are more details to make it cool but will leave it, as it is out of context of this simple question.

Wrong value for statusBarOrientation on viewWillAppear

I need to change the image background of a View depending on the orientation. For this, I am using the statusBarOrientation approach in viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
NSLog(#"PORTRAIT");
} else if (UIInterfaceOrientationIsLandscape(currentOrientation)) {
NSLog(#"LANDSCAPE");
}
}
The problem is that the console is always showing PORTRAIT, even when the iPad is held in landscape mode. The same code in viewDidAppear works correctly, but there is too late and the user can see the change of images. That makes me think that the correct state of statusBarOrientation is still not available in viewWillAppear, but I have read in some other questions that this code should work there.
Try
int type = [[UIDevice currentDevice] orientation];
if (type == 1) {
NSLog(#"portrait default");
}else if(type ==2){
NSLog(#"portrait upside");
}else if(type ==3){
NSLog(#"Landscape right");
}else if(type ==4){
NSLog(#"Landscape left");
}
You shouldn't be using the statusBarOrientation to determine the current orientation of the application. According to Apple's doc: http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html
The value of this property is a constant that indicates an orientation of the receiver's status bar. See UIInterfaceOrientation for details. Setting this property rotates the status bar to the specified orientation without animating the transition. If your application has rotatable window content, however, you should not arbitrarily set status-bar orientation using this method. The status-bar orientation set by this method does not change if the device changes orientation.
Try using the interfaceOrientation property of a UIViewController to get the orientation of the current application.
Here is a useful code snippet for logging the device's interfaceOrientation:
NSArray* orientations = #[ #"nothing", #"UIInterfaceOrientationPortrait", #"UIInterfaceOrientationPortraitUpsideDown", #"UIInterfaceOrientationLandscapeLeft", #"UIInterfaceOrientationLandscapeRight”];
NSLog(#"Current orientation := %#", orientations[self.interfaceOrientation]);
Hope this helps someone out!

How to get device orientation via UIView reference?

I need to get device orientation from a ViewController. I cannot base on:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
because it sometimes returns orientation unknown (for example when the device lays on the table).
I just need to know in what orientation is my current UIView displayed (is it landscape left or landscape right). I don't need to have this value updated when orientation changes, I just want to know it, when I ask for it. Just some reference view.orientation ;). Is there something that would help me? I've read UIView documentation, found some reference to UIWindow, but nothing that could help me.
You can also get the device orientation from UIApplication, have you tried using
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
UIViewController has a property
UIInterfaceOrientation interfaceOrientation;
So in your UIViewController, you can access the current orientation of the device at any time via
UIInterfaceOrientation myCurrentOrientation = self.interfaceOrientation;
Swift Version
let currentOrientation:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
if currentOrientation.isPortrait {
print("PORTRAIT")
} else if currentOrientation.isLandscape {
print("LANDSCAPE")
}
Following is the sample code to do the same. There is a variable named deviceOrientation, and it will answer the current orientation of device, whenever being asked.
UIDeviceOrientation deviceOrientation;
- (void)viewWillAppear:(BOOL)animated
{
deviceOrientation = (UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
[self willAnimateRotationToInterfaceOrientation:deviceOrientation duration:0.5];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
deviceOrientation = (UIDeviceOrientation)interfaceOrientation;
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
NSLog(#"Landscape");
}
else
{
NSLog(#"Portrait");
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return TRUE;
}

Detect iPad orientation when launch a app

Is anyone know a way to detect the orientation of the iPad programmatically when launch a app.
I'm using following mechanism.
- (void) detectDeviceInitialOrientation
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
MyAppDelegate *appDelegate=(MyAppDelegate*)[[UIApplication sharedApplication] delegate];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIDeviceOrientationIsPortrait(orientation)) {
appDelegate.orintation = PORTRAIT;
}
else if (UIDeviceOrientationIsLandscape(orientation)) {
appDelegate.orintation = LANDSCAPE;
}
}
But it fails to detect the device's orientation when it lay parallel to the floor. So, I'm looking another solution. Please help......
Have a look at the UIDeviceOrientation enum in the docs.
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
Notice that this defines UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown. Unfortunately, there is no built in check for whether the device is in one of these orientations like there is for portrait or landscape. However, you can do the checking your self with a simple if statement. Something like this:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown) {
// device is flat on the ground
}

iOS: How do I figure out the current orientation in viewWillAppear?

I have a UIWebView that I would like to load different URLs depending on whether its portrait or landscape. How can I figure out what my current orientation is inside viewWillAppear?
Use UIApplication's statusBarOrientation property. You may run into problems if you use the device orientation if it is UIDeviceOrientationFaceUp or UIDeviceOrientationFaceDown.
Example
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(orientation))
{
// Do something when in landscape
}
else
{
// Do something when in portrait
}
UIDeviceOrientation getCurrentOrientation() {
UIDevice *device = [UIDevice currentDevice];
[device beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation currentOrientation = device.orientation;
[device endGeneratingDeviceOrientationNotifications];
return currentOrientation;
}
It's up to you to convert the UIDeviceOrientation to UIInterfaceOrientation.
When the app loads, it does not know its current orientation-
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationPortrait) {
NSLog(#"portrait");// only works after a rotation, not on loading app
}
Once you rotate the device, you get correct orientation, but when the app is loaded, without changing the orientation, it seems that using [[UIDevice currentDevice] orientation] doesn't know the current orientation.
So you need to do 2 things -
Try setting the application's accepted device orientations in the plist file
In your UIViewControllers, you will need to override the shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) method to return YES when the app should rotate:
If the is sequencing of relevant calls mean that you can't rely on interfaceOrientation having the correct value at viewWillAppear then — assuming the parent view controller rotates — the safest thing is probably self.parentViewController.interfaceOrientation. Failing that you could try making a first assumption from [[UIDevice currentDevice] orientation], which may not always be 100% on the money (e.g. if the device is lying flat on a table when your app is launched) but is likely to give you a better guess than always assuming portrait.

Resources