[UIScreen mainScreen] .bounds.size在iOS8中是否与方向相关?


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中的临时错误?


13
好吧,iOS8的输出似乎更具逻辑性
Levi

Answers:


173

是的,它在iOS8中取决于方向,不是错误。您可以查看来自WWDC 2014的会话214,以了解更多信息:“ iOS 8中的View Controller Advances”

演讲中的引用:

UIScreen现在是面向接口的:

  • [UIScreen边界]现在面向界面
  • [UIScreen applicationFrame]现在面向界面
  • 状态栏框架通知是面向界面的
  • 键盘框架通知是面向接口的

7
在上述WWDC讲座中,面向接口的部分始于51:50。
cnotethegr8 2014年

2
我今天大部分时间都在努力解决这一进步。显然,这种情况并非总是会发生,因此,如果您是需要在其他应用程序中工作的SDK开发人员,那么这些事情将变得更加复杂。
Glenn Maynard 2014年

1
@aroth,如果不克服一些老习惯,就无法创新。
鲍里斯Y.

23
@borisy-我谨表示不同意。在大多数情况下,可以在保持向后兼容性的同时进行创新。在我看来,打破变化比其他任何事情都要懒惰。他们希望其他人都去做。
aroth

1
如果解释了面向接口的实际含义,那么该答案将更加有用。我可能是错的,但我认为方向依赖性仅与视图控制器有关。如果您选择其他任何类别并计算边界,它们仍然按照旧样式,始终为纵向。
Maxi Mus

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

1
我编辑了代码,请检查,您检查操作系统版本的条件有误
Jageen 2014年

@Jageen请澄清,版本检查对我有用。问题是什么?
cbartel

我的理解是,如果OS是iOS8,方向是风景,我们需要更改高度和宽度,对吗?
贾根2014年

@Jageen Negative,在iOS 8中,该方法取决于方向。您的逻辑已切换。您的修改已被正确拒绝。
cbartel

@cbartel是否可以将其分类到UIScreen中,以便我们对[UIScreen mainScreen] .bounds.size的原始调用将同时适用于iOS 7和iOS 8?
kevinl 2014年

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

2
我发现这可以解决常规iPhone应用程序的问题,但不能解决iPad上运行的iPhone应用程序的问题。
ThomasW

32

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

我更喜欢以下以与方向无关的方式获取屏幕尺寸的方法,而不是上面的某些答案,这既是因为它更简单,又因为它不依赖于任何方向代码(其状态可以取决于屏幕方向)。调用它们的时间)或进行版本检查。您可能需要新的iOS 8行为,但是如果您希望它在所有版本的iOS上都稳定,则可以使用该行为。

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

不过,在Apple TV之类的设备上,它(几乎)总是比它的高度高,可能无法正常工作。
cbh2000

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,则这是解决此问题的最佳方法。


@Namit Gupta,您的编辑有误。如果IOS版本为8或更高版本,我们可以使用UIScreen尺寸,因为这些尺寸取决于方向。在iOS 8之前,您必须检查状态栏的方向。您的编辑现在说所有不低于8的iOS版本都应检查statusbarorientation,这是错误的。
Antoine 2014年

9

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

nativeBounds

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

声明SWIFT

  var nativeBounds: CGRect { get }

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

检测设备的高度:

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

}

检测设备的宽度:

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

}

3
请注意,此方法返回像素,而其他大多数方法都处理点。完全不同的东西。
jcsahnwaldt恢复莫妮卡2015年

1
就我而言,正是我所需要的:)(OpenGL或其他基于
UIViews的

3
警告:在iPhone 6+上,这返回了1080 x 1920,这可能不是您想要的
Chanon 2015年

8

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


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

1
如果同事正在使用不同版本的SDK构建您的应用程序,那么检查SDK版本也是一个很好的提示(尽管这不应该发生!)。
Craig McMahon 2014年

4

我的解决方案是MaxK和hfossli的结合。我在UIScreen的Category上创建了此方法,并且没有版本检查(这是一种不好的做法):

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

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

令人讨厌,但是要做好工作,直到可以将时间放到正确解决问题的地方:-)
DuneCat 2014年

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

1

那就是我用来计算正确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

1

只需添加上述出色的cbartel功能的快速版本即可。

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
}

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

它的工作对我来说就是尝试。


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

0

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

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

重新排列Info.plist中的itens,将Portrait放在第一位,恢复了预期的行为。


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


问题不在于基于屏幕分辨率的设备识别。此外,苹果建议创建基于尺寸类别的自适应UI,而不是基于设备/屏幕检测
朱利安·克罗尔(JulianKról)2015年

0

使用经过稍微修改的mnemia解决方案,该解决方案无需iOS版本检查,而是在主屏幕边界上使用min / max。
我需要一个CGRect这样了CGRect来自mainscreen范围和改变size.width=min(w,h)size.height=max(w,h)。然后,我CGRect在代码的两个位置调用了与操作系统无关的get 函数,在该位置获取屏幕尺寸OpenGL,触摸等。修复之前,我遇到了2个问题-在IOS 8.x上以横向模式显示OpenGL视图的位置不正确:1 /全屏显示在左下方的4。第二次触摸返回无效值。如所解释的,两个问题都已解决。谢谢!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.