184

我在 iOS 7 和 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);

以下是 iOS 8 的结果:

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

与 iOS 7 中的结果比较:

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

是否有任何文件说明此更改?或者它是 iOS 8 API 中的一个临时错误?

4

18 回答 18

174

是的,它在 iOS8 中取决于方向,而不是错误。您可以查看 WWDC 2014 中的会话 214 以获取更多信息:“查看 iOS 8 中的控制器进步”

演讲中的引述:

UIScreen 现在是面向界面的:

  • [UIScreen bounds] 现在面向界面
  • [UIScreen applicationFrame] 现在面向界面
  • 状态栏框架通知是面向界面的
  • 键盘框架通知是面向界面的
于 2014-06-11T01:59:04.313 回答
59

是的,它在 iOS8 中取决于方向。

我为需要支持旧版本操作系统的应用程序编写了一个 Util 方法来解决此问题。

+ (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;
}
于 2014-08-01T20:50:54.727 回答
34

是的,确实,屏幕尺寸现在在 iOS 8 中取决于方向。然而,有时需要将尺寸固定为纵向。这是我的做法。

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

    if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) {
                    return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace];
    } 
    return screen.bounds;
}
于 2014-08-08T18:11:07.290 回答
32

是的,它现在取决于方向。

对于上面的一些答案,我更喜欢以下以与方向无关的方式获取屏幕尺寸的方法,因为它更简单,而且它不依赖于任何方向代码(其状态可能取决于它们被调用的时间)或版本检查。您可能想要新的 iOS 8 行为,但如果您需要它在所有版本的 iOS 上保持稳定,这将起作用。

+(CGSize)screenSizeOrientationIndependent {
     CGSize screenSize = [UIScreen mainScreen].bounds.size;
     return CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
}
于 2014-09-23T18:48:51.843 回答
11

与这个问题相关,因为它解决了我的问题,这里有两个定义我用于屏幕宽度和高度计算:

#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)

如果您同时支持 iOS 7 和 iOS 8,这是解决此问题的最佳解决方案。

于 2014-10-18T13:52:05.813 回答
9

您可以使用nativeBounds(与方向无关)

本机边界

物理屏幕的边界矩形,以像素为单位。(只读)

声明 SWIFT

  var nativeBounds: CGRect { get }

此矩形基于纵向向上的设备。该值不会随着设备的旋转而改变。

检测设备的高度:

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

}

检测设备的宽度:

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

}
于 2015-01-04T00:20:59.930 回答
8

这不是 iOS 8 SDK 中的错误。他们使边界界面方向依赖。根据您关于该事实的一些参考或文档的问题,我强烈建议您观看WWDC 2014View Controller Advancements in iOS 8的 214 session 。最有趣的部分(根据您的疑问)是从 50:45 开始的。Screen Coordinates

于 2014-08-05T13:41:25.787 回答
5

是的,它在 iOS8 中取决于方向。

以下是如何以 iOS 8 方式跨 SDK 和 OS 版本以一致的方式读取边界。

#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
于 2014-09-11T15:49:11.627 回答
4

我的解决方案是 MaxK 和 hfossli 的组合。我在 UIScreen 类别上制作了这个方法,它没有版本检查(这是一个不好的做法):

//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;
}
于 2014-10-14T21:09:44.753 回答
3

我需要一个快速帮助函数,它在 iOS8 下保持与 iOS7 相同的行为——这让我可以交换我的[[UIScreen mainScreen] bounds]调用而不接触其他代码......

+ (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;
}
于 2014-10-08T05:32:07.723 回答
3

以下方法可用于查找给定方向的屏幕边界,与 iOS 版本无关。此方法将根据设备的屏幕大小返回边界,并给出与 iOS 版本无关的相同 CGRect 值。

- (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]; 
于 2014-11-11T06:17:26.310 回答
1

我的问题与正在减去的 UIWindows 框架有关。所以在 MyViewController -(NSUInteger)supportedInterfaceOrientations 方法中制作了如下代码

[[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)];

它的工作对我来说试试吧。

于 2015-01-29T13:17:53.093 回答
1

只需添加上面回答的出色 cbartel 函数的 swift 版本即可。

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
}
于 2015-01-03T22:11:43.510 回答
1

这就是我用来计算正确矩形的方法:

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
于 2014-10-28T09:29:52.117 回答
1

iOS 8 或更高版本

对于那些想要以点为单位计算屏幕尺寸(3.5 英寸屏幕有 320 × 480 点,4.0 英寸屏幕有 320 × 568 点等)的解决方案将是

- (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;
    }
}
于 2015-12-03T18:32:55.073 回答
0

这将在iOS7iOS8中提供正确的设备,

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

//您也可以添加更多设备(即iPad)。

于 2015-03-23T09:33:58.597 回答
0

我注意到的一件事是,Info.plist 中支持的界面方向的顺序确​​实很重要。我的应用程序(在代码中执行方向)遇到了这个问题的问题,但我没有指定默认方向是纵向的任何地方。

我认为无论如何默认方向都是纵向的。

重新排列 Info.plist 中的项目,将肖像放在首位,恢复了预期的行为。

于 2014-09-26T19:35:42.950 回答
0

使用稍微修改过的 mnemia 的解决方案,即没有 iOS 版本检查的解决方案,在主屏幕边界上使用 min/max。
我需要一个从主屏幕边界得到的结果并改变CGRect了, . 然后我在我的代码中的两个地方调用了与操作系统无关的 get函数,在那里我获取屏幕尺寸、触摸等。在修复之前我遇到了 2 个问题 - 在横向模式下的 IOS 8.x 上,视图的显示位置不正确:1/左下角全屏4。第二次触摸返回无效值。这两个问题都已按照说明进行了修复。谢谢!CGRectsize.width=min(w,h)size.height=max(w,h)CGRectOpenGLOpenGL

于 2015-01-26T07:34:41.210 回答