Is [UIScreen mainScreen].bounds.size becoming orientation-dependent in iOS8?

IosIos8OrientationUiinterfaceorientationUiscreen

Ios Problem Overview


I ran the following code in both iOS 7 and iOS 8:

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
BOOL landscape = (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight);
NSLog(@"Currently landscape: %@, width: %.2f, height: %.2f", 
      (landscape ? @"Yes" : @"No"), 
      [[UIScreen mainScreen] bounds].size.width, 
      [[UIScreen mainScreen] bounds].size.height);

The following is the result from iOS 8:

Currently landscape: No, width: 320.00, height: 568.00
Currently landscape: Yes, width: 568.00, height: 320.00

Comparing to the result in iOS 7:

Currently landscape: No, width: 320.00, height: 568.00
Currently landscape: Yes, width: 320.00, height: 568.00

Is there any documentation specifying this change? Or is it a temporary bug in iOS 8 APIs?

Ios Solutions


Solution 1 - Ios

Yes, it's orientation-dependent in iOS8, not a bug. You could review session 214 from WWDC 2014 for more info: "View Controller Advancements in iOS 8"

Quote from the presentation:

UIScreen is now interface oriented:

  • [UIScreen bounds] now interface-oriented

  • [UIScreen applicationFrame] now interface-oriented

  • Status bar frame notifications are interface-oriented

  • Keyboard frame notifications are interface-oriented

Solution 2 - Ios

Yes, it's orientation-dependent in iOS8.

I wrote a Util method to resolve this issue for apps that need to support older versions of the OS.

+ (CGSize)screenSize {
	CGSize screenSize = [UIScreen mainScreen].bounds.size;
	if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
		return CGSizeMake(screenSize.height, screenSize.width);
	}
	return screenSize;
}

Solution 3 - Ios

Yes, indeed, screen size is now orientation dependent in iOS 8. Sometimes, however, it's desired to get a size fixed to portrait orientation. Here is how I do it.

+ (CGRect)screenBoundsFixedToPortraitOrientation {
    UIScreen *screen = [UIScreen mainScreen];

    if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) {
                    return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace];
    } 
    return screen.bounds;
}

Solution 4 - Ios

Yes, it's now dependent on orientation.

I prefer the below method of getting the screen size in an orientation-independent way to some of the answers above, both because it's simpler and because it doesn't depend on any of the orientation code (the state of which can be dependent on the time that they are called) or on version checking. You may want the new iOS 8 behavior, but this will work if you need it to be stable on all versions of iOS.

+(CGSize)screenSizeOrientationIndependent {
     CGSize screenSize = [UIScreen mainScreen].bounds.size;
     return CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
}

Solution 5 - Ios

Related to this question as it solved my problem, here two defines I use for screen width and height calculations:

#define SCREEN_WIDTH (IOS_VERSION_LOWER_THAN_8 ? (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height) : [[UIScreen mainScreen] bounds].size.width)

#define SCREEN_HEIGHT (IOS_VERSION_LOWER_THAN_8 ? (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width) : [[UIScreen mainScreen] bounds].size.height)

#define IOS_VERSION_LOWER_THAN_8 (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)

If you are supporting both iOS 7 and iOS 8, this is the best solution for this problem.

Solution 6 - Ios

You can use nativeBounds (orientation-independent)

nativeBounds > The bounding rectangle of the physical screen, measured in pixels. > (read-only) > > Declaration SWIFT

> var nativeBounds: CGRect { get }

>
> This rectangle is based on the device in a portrait-up orientation. This > value does not change as the device rotates. >

Detecting the device's height:

if UIScreen.mainScreen().nativeBounds.height == 960.0 {
  
}

Detecting the device's width:

if UIScreen.mainScreen().nativeBounds.width == 640.0 {

}

Solution 7 - Ios

It is not a bug in iOS 8 SDK. They made bounds interface orientation depended. According to your question about some reference or documentation to that fact I will highly recommend you to watch View Controller Advancements in iOS 8 it is 214 session from WWDC 2014. The most interesting part (according to your doubts) is Screen Coordinates which starts at 50:45.

Solution 8 - Ios

Yes, it's orientation-dependent in iOS8.

Here's how you can have a concistent way of reading out bounds in an iOS 8 fashion across SDK's and OS-versions.

#ifndef NSFoundationVersionNumber_iOS_7_1
# define NSFoundationVersionNumber_iOS_7_1 1047.25
#endif

@implementation UIScreen (Legacy)

// iOS 8 way of returning bounds for all SDK's and OS-versions
- (CGRect)boundsRotatedWithStatusBar
{
    static BOOL isNotRotatedBySystem;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        BOOL OSIsBelowIOS8 = [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0;
        BOOL SDKIsBelowIOS8 = floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1;
        isNotRotatedBySystem = OSIsBelowIOS8 || SDKIsBelowIOS8;
    });
    
    BOOL needsToRotate = isNotRotatedBySystem && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
    if(needsToRotate)
    {
        CGRect screenBounds = [self bounds];
        CGRect bounds = screenBounds;
        bounds.size.width = screenBounds.size.height;
        bounds.size.height = screenBounds.size.width;
        return bounds;
    }
    else
    {
        return [self bounds];
    }
}

@end

Solution 9 - Ios

My solution is a combination of MaxK's and hfossli. I made this method on a Category of UIScreen and it has no version checks (which is a bad practice):

//Always return the iOS8 way - i.e. height is the real orientation dependent height
+ (CGRect)screenBoundsOrientationDependent {
    UIScreen *screen = [UIScreen mainScreen];
    CGRect screenRect;
    if (![screen respondsToSelector:@selector(fixedCoordinateSpace)] && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        screenRect = CGRectMake(screen.bounds.origin.x, screen.bounds.origin.y, screen.bounds.size.height, screen.bounds.size.width);
    } else {
        screenRect = screen.bounds;
    }
    
    return screenRect;
}

Solution 10 - Ios

I needed a quick helper function that kept the same behavior as iOS7 under iOS8 - this allowed me to swap out my [[UIScreen mainScreen] bounds] calls and not touch other code...

+ (CGRect)iOS7StyleScreenBounds {
    CGRect bounds = [UIScreen mainScreen].bounds;
    if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        bounds.size = CGSizeMake(bounds.size.height, bounds.size.width);
    }
        return bounds;
}

Solution 11 - Ios

The below method can be used to find the screen bounds for a given orientation, independent of iOS version. This method will return the bounds based on the screen size of the device and will give the same CGRect value independent of iOS version.

- (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation {

    CGFloat width   = [[UIScreen mainScreen] bounds].size.width;
    CGFloat height  = [[UIScreen mainScreen] bounds].size.height;
    
    CGRect bounds = CGRectZero;

    if (UIInterfaceOrientationIsLandscape(orientation)) {
        bounds.size = CGSizeMake(MAX(width, height), MIN(width, height));
    } else {
        bounds.size = CGSizeMake(MIN(width, height), MAX(width, height));
    }

    return bounds;
}

// For the below example, bounds will have the same value if you run the code on iOS 8.x or below versions.
CGRect bounds = [self boundsForOrientation:UIInterfaceOrientationPortrait]; 

Solution 12 - Ios

Thats what I used to calculate the correct rect:

UIScreen* const mainScreen = [UIScreen mainScreen];
CGRect rect = [mainScreen bounds];
#ifdef __IPHONE_8_0
if ([mainScreen respondsToSelector:@selector(coordinateSpace)])
{
    if ([mainScreen respondsToSelector:@selector(fixedCoordinateSpace)])
    {
        id tmpCoordSpace = [mainScreen coordinateSpace];
        id tmpFixedCoordSpace = [mainScreen fixedCoordinateSpace];
        
        if ([tmpCoordSpace respondsToSelector:@selector(convertRect:toCoordinateSpace:)])
        {
            rect = [tmpCoordSpace convertRect:rect toCoordinateSpace: tmpFixedCoordSpace];
        }
    }
}
#endif

Solution 13 - Ios

Just adding the swift version of an excellent cbartel function answered above.

func screenSize() -> CGSize {
    let screenSize = UIScreen.mainScreen().bounds.size
    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
        return CGSizeMake(screenSize.height, screenSize.width)
    }
    return screenSize
}

Solution 14 - Ios

My issue was related to UIWindows frame which was going in minus. So made the code as below in MyViewController -(NSUInteger)supportedInterfaceOrientations Method

[[UIApplication sharedApplication] setStatusBarHidden:NO];

[self.view setFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];

[appDel.window setFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];

And its work for me try it.

Solution 15 - Ios

iOS 8 or upper

A solution for those who want to find out the screen size in points (3.5 inches screen has 320 × 480 points, 4.0 inches screen has 320 × 568 points, etc) would be

- (CGSize)screenSizeInPoints
{
    CGFloat width = [[UIScreen mainScreen] bounds].size.width;
    CGFloat height = [[UIScreen mainScreen] bounds].size.height;
    
    if (width > height) {
        return CGSizeMake(height, width);
    }
    else {
        return [[UIScreen mainScreen] bounds].size;
    }
}

Solution 16 - Ios

One thing that I noted is, the order of supported interface orientations in Info.plist does matter. I got the problem of this question with my app (that does orientation in code), but I did not specify anywhere that default orientation is Portrait.

I thought that default orientation was Portrait in any case.

Rearranging itens in Info.plist, putting Portrait first, restored the expected behavior.

Solution 17 - Ios

Used slightly modified mnemia's solution, that one without iOS version check, using min/max on mainscreen bounds.
I needed a CGRect so got CGRect from mainscreen bounds and changed size.width=min(w,h), size.height=max(w,h). Then I called that OS-independent get CGRect function in two places in my code, where I getting screen size for OpenGL, touches etc. Before fix I had 2 problems - on IOS 8.x in landscape mode display position of OpenGL view was incorrect: 1/4 of full screen in left bottom part. And second touches returned invalid values. Both problems were fixed as explained. Thanks!

Solution 18 - Ios

This will give correct device in iOS7 and iOS8 both,

#define SYSTEM_VERSION_LESS_THAN(v)	([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define IS_PORTRAIT			UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)

+ (BOOL)isIPHONE4{

// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
	
		if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 480.0) {
			return YES;
		} else {
			return NO;
		}

// >= iOS 8.0
}else{

	if(IS_PORTRAIT){
	
		if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 480.0) {
			return YES;
		} else {
			return NO;
		}
	
	}else{
	
		if ([self getDeviceWidth] == 480.0 && [self getDeviceHeight] == 320.0) {
			return YES;
		} else {
			return NO;
		}
		
	}

}


}

+ (BOOL)isIPHONE5{


// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
	
	if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 568.0) {
		return YES;
	} else {
		return NO;
	}
	
	// >= iOS 8.0
}else{
	
	if(IS_PORTRAIT){
		
		if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 568.0) {
			return YES;
		} else {
			return NO;
		}
		
	}else{
		
		if ([self getDeviceWidth] == 568.0 && [self getDeviceHeight] == 320.0) {
			return YES;
		} else {
			return NO;
		}
		
	}
	
}

}

+ (BOOL)isIPHONE6{

// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
	
	if ([self getDeviceWidth] == 375.0 && [self getDeviceHeight] == 667.0) {
		return YES;
	} else {
		return NO;
	}
	
	// >= iOS 8.0
}else{
	
	if(IS_PORTRAIT){
		
		if ([self getDeviceWidth] == 375.0 && [self getDeviceHeight] == 667.0) {
			return YES;
		} else {
			return NO;
		}
		
	}else{
		
		if ([self getDeviceWidth] == 667.0 && [self getDeviceHeight] == 375.0) {
			return YES;
		} else {
			return NO;
		}
		
	}
	
}


}
+ (BOOL)isIPHONE6Plus{


// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){
	
	if ([self getDeviceWidth] == 414.0 && [self getDeviceHeight] == 736.0) {
		return YES;
	} else {
		return NO;
	}
	
	// >= iOS 8.0
}else{
	
	if(IS_PORTRAIT){
		
		if ([self getDeviceWidth] == 414.0 && [self getDeviceHeight] == 736.0) {
			return YES;
		} else {
			return NO;
		}
		
	}else{
		
		if ([self getDeviceWidth] == 736.0 && [self getDeviceHeight] == 414.0) {
			return YES;
		} else {
			return NO;
		}
		
	}
	
}


}

+ (CGFloat)getDeviceHeight{

//NSLog(@"Device width: %f",[UIScreen mainScreen].bounds.size.height);
return [UIScreen mainScreen].bounds.size.height;
}
+ (CGFloat)getDeviceWidth{

//NSLog(@"Device width: %f",[UIScreen mainScreen].bounds.size.height);
return [UIScreen mainScreen].bounds.size.width;
}

//You may add more devices as well(i.e.iPad).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlwxtedView Question on Stackoverflow
Solution 1 - IosvhristoskovView Answer on Stackoverflow
Solution 2 - IoscbartelView Answer on Stackoverflow
Solution 3 - IosMaxKView Answer on Stackoverflow
Solution 4 - IosmnemiaView Answer on Stackoverflow
Solution 5 - IosAntoineView Answer on Stackoverflow
Solution 6 - IosLeo DabusView Answer on Stackoverflow
Solution 7 - IosJulianView Answer on Stackoverflow
Solution 8 - IoshfossliView Answer on Stackoverflow
Solution 9 - IosUzair KhanView Answer on Stackoverflow
Solution 10 - IosJoe BoothView Answer on Stackoverflow
Solution 11 - Iosuser4226071View Answer on Stackoverflow
Solution 12 - IoshhammView Answer on Stackoverflow
Solution 13 - IosMartin KolesView Answer on Stackoverflow
Solution 14 - IosHardik MamtoraView Answer on Stackoverflow
Solution 15 - IosnsinvocationView Answer on Stackoverflow
Solution 16 - IosepxView Answer on Stackoverflow
Solution 17 - IosNoAngelView Answer on Stackoverflow
Solution 18 - IosMohammad Zaid PathanView Answer on Stackoverflow