Where can I get a rotation specific appFrame? - iphone

How can I retrieve a rotation specific applicationFrame/screen bounds? The "applicationFrame" method always returns 768x1024 on the iPad, no matter whether the device is in landscape or portrait mode. I am looking for a method that would return me 1024x768 if the device is in landscape and 768x1024 if its in portrait.
I am sure there is something like this out there but I just can't find it. In case it really doesn't exist, how do make your iPad apps landscape and portrait compatible?

[UIDevice currentDevice].orientation
Will return one of
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
From there, you can deduce what the current frame should be.

Turns out applicationFrame works fine, but only if the autorotation is properly implemented! In my case the controller of the view that was added as subview to the UIWindow was released too early, which seems to cause applicationFrame to break along with the autorotation mechanism. I think this is because the responder chain can no longer function properly, yet I did not verify this.

Related

Why the [UIApplication sharedApplication].statusBarOrientation returns wrong values

Hi in my application i would like to know the statusbarorientation value. For that i am using [UIApplication sharedApplication].statusBarOrientation method. Actually this method have to return 4 for landscape and 2 for potrait mode. But this method returning the values in opposite way. Means for landscape 2 and for potrait 4. Please let me know how to fix this issue.In supportedInterfaceOrientations method i am using return UIInterfaceOrientationMaskAll;
Please help me in resolving this issue.
It probably happens because the UIDeviceOrientationLandscapeRight is assigned to UIInterfaceOrientationLandscapeLeft and UIDeviceOrientationLandscapeLeft is assigned to UIInterfaceOrientationLandscapeRight.
The reason for this is that rotating the device requires rotating the content in the opposite direction.
Starting in iOS 8, you should use the UITraitCollection and UITraitEnvironment APIs, and size class properties as used in those APIs, rather than using UIInterfaceOrientation constants or otherwise writing your app in terms of interface orientation.
Anyway, taking the orientation in this way worked for me.
var orientation = UIApplication.SharedApplication.StatusBarOrientation;
switch (orientation)
{
case UIInterfaceOrientation.PortraitUpsideDown:
// The device is in portrait mode but upside down, with the device held upright and the home button at the top.
case UIInterfaceOrientation.Portrait:
// The device is in portrait mode, with the device held upright and the home button on the bottom.
case UIInterfaceOrientation.LandscapeLeft:
// The device is in landscape mode, with the device held upright and the home button on the left side.
case UIInterfaceOrientation.LandscapeRight:
// The device is in landscape mode, with the device held upright and the home button on the right side.
case UIInterfaceOrientation.Unknown
// The orientation of the device cannot be determined.
}
Consider also that
If your app 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.

UIDevice Orientation

How to find out if the UIDeviceOrientationFaceUp is landscape FaceUp or Portrait FaceUp?
Can any one tell me?
UIDeviceOrientation will only tell you the orientation of the physical device. You need to use methods that use UIInterfaceOrientation (from UIApplication) to make decisions depending on whether the screen is in portrait and landscape mode.
You can use UIInterfaceOrientationIsLandscape() and UIInterfaceOrientationIsPortrait() with a UIInterfaceOrientation too.
I realise this is an old question now, but looking at the answers everyone is being overly pedantic. In case anyone else stumbles across this:
The answer to your problem is for you to keep a secondary variable which is any of your accepted orientations.
When the device orientation notification comes in, simply look at the incoming orientation and see if its an acceptable one, (portrait/landscape NOT faceup/facedown) then update your secondary variable, and finally trigger a ui/app refresh from there using your secondary variable as the orientation source.
This will have the effect of locking the orientation to the "last known good" orientation.
It's not possible, because the accelerometer can't detect rotation around the z axis. On an iPhone 4, you could perhaps use the gyroscope for this (using CoreMotion), but UIDevice doesn't have an API for this. You would then also have to define what the starting position is, because you can't detect in which direction the user is from the device's point of view.
UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown are orientations for when the device is laying flat (like on a table). Portrait and Landscape don't make sense in this cases.
There is no way you can find out from orientation . I have found a workaround.
CGRect screenBounds = [[UIScreen mainScreen]bounds];
if(screenBounds.size.width > screenBounds.size.height)
{
// This means FaceUP/Down is in Landscape
}
else
{
// This means FaceUp/Down is in Portrait
}

How to get InterfaceOrientation from iPhone (not DeviceOrientation)?

I've created a modalviewcontroller and all the subviews are created by code. When I'm testing the app, I find a problem. Then main cause of the problem is that an app shouldn't support UpsideDown orientation, but devices may happen to be in that orientation.
If I:
Rotate the device to Portrait orientation, and then to UpsideDown mode and presentModalView, the subviews in modalviewcontroller should appear the same as Portrait orientation.
Rotate the device to Landscape orientation, and then to UpsideDown mode and presentModalView, the subviews should be treated differently.
The above situation tells me that I should create subviews in modalviewcontroller according to previous InterfaceOrientation.
The problem is: How to get the previous screen's InterfaceOrientation? Getting the device orientation won't do any help in this situation.
PS: I'm writing a lib, I may give my users the interface to send me the "toInterfaceOrientation" from -willRotateToInterfaceOrientation:duration: but are there any ideas about how to get the orientation in my code?
In any UIViewController you can access the property interfaceOrientation like this:
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
// do stuff
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

Launching application in landscape orientation for IPad

Facing one issue with launching application in landscape orientation for IPad.
I have developed IPhone application which later I ported to IPad.
I have made setting regarding orientation in info.plist
[ UISupportedInterfaceOrientations~ipad ] to support all orientation UIInterfaceOrientationPortrait , UIInterfaceOrientationPortraitUpsideDown , UIInterfaceOrientationLandscapeLeft , UIInterfaceOrientationLandscapeRight.
but when I start IPad application in the landscape mode, it always start in the potrait mode.
Along this
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{ return YES; }
help me, if I am missing something with this..
Thanks,
Sagar
here's something I also discovered: setting the initial interface orientation in your info.plist is being ignored if you have Supported interface orientations set up with another orientation in the first slot! Put your initial orientation there as well - and the simulator will launch correctly, as will the app. this drove me nuts for a long time!
Put UISupportedInterfaceOrientations into your -Info.plist, with a setting for each orientation you support. This is used to see which orientation the app can start in. From there onwards it will ask your view controllers.
Sagar - I had the same issue but was able to resolve it.
Like yours, my app started as an iPhone app which I "upgraded" to a Universal app using the XCode wizard. I noticed that when running on the actual iPad, starting in landscape, the app would start in Portrait, then maybe rotate to Landscape. On the simulator, starting in landscape, the app would start in Landscape, then the simulator would rotate to Portrait.
On the iPad, my app is a split-view app with TabBarControllers on left and right. Each tab is a view controller that returns YES to shouldAutoRotateToInterfaceOrientation.
I noticed that a brand-new wizard-generated, simple-case with a splitviewcontroller, Universal app didn't have this problem.
The difference I found between my app and the simple-case was that I wasn't adding my splitview-controller's view to the app window in applicationDidFinishLaunchingWithOptions. Instead I was showing a "loading" view at this stage, then later when an initialization thread completed I'd add my splitviewcontroller's view (and hide the "loading" view).
When I added my splitviewcontroller's view to the app window during the call to applicationDidFinishLaunchingWithOptions everything started working fine.
There must be some magic that happens on return from applicationDidFinishLaunchingWithOptions???
Is your app similar to mine in that it isn't adding the main view controller's view to the window during applicationDidFinishLaunchingWithOptions?
As pointed out in a number of posts, you must set up the info.plist with both the supported and the initial interface orientations. However, the bigger issue is when does the initial orientation become effective? The answer is NOT when your view controller receives the "viewDidLoad" message. I found that on the iPad-1, running iOS 5.0, the requested initial orientation becomes effective only after several "shouldAutorotateToInterfaceOrientation"
messages are received.(This message passes the UIInterfaceOrientation parameter to the receiver.) Furthermore, even if the orientation says it is in Landscape mode, it may not be! The only way I found to be sure that the view is in Landscape mode is to test that the view height is less than the view width.
The strategy that worked for me was to lay out the subViews I wanted when the "viewDidLoad" message was received but to delay actually adding those subViews to the view until the controller received a valid "shouldAutorotate.." message with the orientation set to Landscape mode. The code looks something like:
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
// N.B. Even when the interface orientation indicates landscape mode
// this may not really be true. So we insure this is so by testing
// that the height of the view is less than the width
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
CGRect viewBounds = [[self view] bounds];
if ( viewBounds.size.height < viewBounds.size.width )
[self addMySubViews];
return YES;
}
else
return NO;
}
Apple has just released iOS 5.1, so this behavior may have changed. But I expect the code that is here should still work.

Determine UIInterfaceOrientation on iPad

I don't need to specify the orientation in this case, I just need to detect it, but I'm having trouble. I have conditional code that should only work in portrait, and if the device is in landscape I need to do something else. Since the deviceOrientation is not necessarily the same as the interfaceOrientation, I can't come up with a way to test for portrait mode.
Most tutorials I find on Google are ways to force landscape or do some sort of rotation. The only thing I want to do is just determine what the orientation is. Here is my code, which is not working:
-(void)viewDidLoad {
[super viewDidLoad];
//currentOrientation is declared as UIInterfaceOrientation currentOrientation
currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
NSLog(#"%#",currentOrientation); // == NULL
}
I need to determine the value of the interfaceOrientation and program conditionally. Thanks for your help!
Are you aware of the interfaceOrientation property of the UIViewController class?
- (void) viewDidLoad {
[super viewDidLoad];
BOOL isPortrait = UIDeviceOrientationIsPortrait(self.interfaceOrientation);
// now do whatever you need
}
Or are you after [[UIDevice currentDevice] orientation]?
Especially at launch I have found the following to be always accurate for the UI, regardless of what the UIDevice says the orientation is.
[UIApplication sharedApplication].statusBarOrientation
self.interfaceOrientation is unreliable in certain situations. For example, re-arranging tabs in a tabbar application returns incorrect value.
However [UIApplication sharedApplication].statusBarOrientation is always reliable. You saved me a lot of time slycrel. Thank you.
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if ((orientation == UIInterfaceOrientationLandscapeLeft)
|| (orientation == UIInterfaceOrientationLandscapeRight) )
{
//Landscape
}
else
{
//Portrait
}
I know it is a very old post. How ever I would like to add a point to say it is better to check status bar orientation is better. When ever you call self.interfaceorientation it is calling shouldRotateToOrientation every time. If you have written some code in that method it will be executed. So be cautious!.
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
if(deviceOrientation == UIDeviceOrientationFaceUp || deviceOrientation == UIDeviceOrientationFaceDown){
if(debug){
NSLog(#"Nothing to change because it is gone to Flat");
}
return;
}
if(deviceOrientation !=statusBarOrientation){
if(debug){
NSLog(#"\nApple has a bug?:\n UIDeviceOrientation : %d, UIInterfaceOrientation: %d",deviceOrientation, statusBarOrientation );
}
}
You won't believe me until you will see at the console the second output!
Some situations - and they exists! - is displayed the last NSLog content!
Than you have to do some workarounds to go on that way, where iOS has no bug, good luck for everyone!
Ah that ... forum moderator maybe will delete this post too, because this doesn't meant to be and answer in his opinion!
I hope it helps for somebody once, it happens on iphone too...(there I got)
Mix it up a little:
BOOL isLandscape = self.view.frame.size.width > self.view.frame.size.height;
(edit) Obviously the previous answers are the correct way to do this and this solution would fail in a situation where view controllers are not full-screen.
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{</br>
if (UIDeviceOrientationIsLandscape(toInterfaceOrientation)) {</br>
some instructions;
} else {
some instructions;
}
}
This is a snippet from one of my programs.
You could of course use the if statement in your ViewDidLoad notification as well.
I already voted up the answer by #slycrel, but I would like to take the time to write this, and point some things out that seems to be lost in this old question, and lots of other questions on the subject.
It's true that Apple does not really want us to update most of our UI based on orientation changes, but it is still totally possible and sometimes necessary on a case by case scenario, and it will be that way until Apple improves their new(ish) APIs (e.g. viewWillTransitionToFrame: would be way more useful than viewWillTransitionToSize:. Just sayin')
Why I voted up the answer by #slycrel is related to what you need to keep in mind as the logical difference between UIDeviceOrientation and UIInterfaceOrientation.
Tthe status bar is what denotes an application's currently known UIInterfaceOrientation. All this stuff about FaceUp, FaceDown is only related to a device's orientation, not necessarily your application's. An application does not support device orientations anyway. Really, UIDeviceOrientation can be ignored completely if all you have to do is make sure you layout and animate things appropriately in your interface, which is 99% of an application developer's use cases. This is currently achieved with the status bar's UIInterfaceOrientation from #slycrel's answer:
[UIApplication sharedApplication].statusBarOrientation
It should be noted, the readwrite version of this property is deprecated, the readonly version is not.
Take this example:
I have an application that supports ALL interfaces orientations, and a root view controller that supports them as well.
Now, I am presenting a UIViewController that will result in the status bar orientation to become landscape.
Which landscape orientation (left or right) it goes to is based on what is returned by preferredInterfaceOrientationForPresentation for that view controller, what the current device orientation is, and what interface orientations the view controller supports (see next point).
The status bar will go to landscape, regardless of what the current device orientation is, because this view controller only supports landscape based on what is returned by supportedInterfaceOrientations. Lets say we support both landscape left and right with UIInterfaceOrientationMaskLandscape.
I also want to conditionally animate this view controller into position with a rotation transform. This will only be necessary when going from portrait or portrait upside down, to landscape left or landscape right. Otherwise it will be a more simple presentation animation without rotation.
Then, after some time and device use, I dismiss that view controller.
Now I want to conditionally animate this view controller off the screen with another rotation transform. This will only be necessary when going from landscape left or landscape right, to portrait or portrait upside down. Otherwise it will be a more simple dismissal animation without rotation.
At this point, the status bar's orientation will become whatever the system decides is appropriate for the combination of your root view controller's preferred interface orientation and supported interface orientations, as well as the device's current UIDeviceOrientation.
Since the view controller we are going to supports ALL interface orientations, if your device's orientation is FaceUp or FaceDown, you can not reliably guess the next UIInterfaceOrientation based on UIDeviceOrientation, and you do not have to anyway.
So... status bar orientation to the rescue!
The previous example is possible, because the status bar orientation is not updated when a view controller transition is about to start (the system asks a transition delegate for an animator, etc.). Then it is updated when the transition starts animating (e.g. by the time animationTransition: is called). This way you should have a good comparison just using the initial and current values of the status bar's UIInterfaceOrientation.
Even without using view controller transitions, it should still be safe to update views based on the status bar orientation.
Keep in mind, if you are manually updating the status bar, and if you are not using "View controller-based status bar appearance" in your Info.plist, then your application's logic must be aware when the status bar will and did change orientation. You will probably be looking for a couple NSNotification names for these cases, which are:
UIApplicationWillChangeStatusBarOrientationNotification
UIApplicationDidChangeStatusBarOrientationNotification
As well as these UIApplicationDelegate methods:
- (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration;
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation;
- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window
And this other helpful UIApplication property:
#property(nonatomic,readonly) NSTimeInterval statusBarOrientationAnimationDuration;
As of iOS8, APIs have been deprecated or return unhelpful results such as .FaceUp .FaceDown
This is because Apple does NOT want you to update your UI using orientation, but rather by using size classes, constraints, and proportion (using n% of superview).
Indeed, orientation dependent code might fail to provide good results across the whole range of device and use case (especially multitasking)