如何获得与方向相关的屏幕高度和宽度?


96

我正在尝试以编程方式确定应用程序的当前高度和宽度。我用这个:

CGRect screenRect = [[UIScreen mainScreen] bounds];

但是,无论设备是纵向还是横向,这都会产生320的宽度和480的高度。如何确定主屏幕的当前宽度和高度(即取决于设备方向)?

Answers:


164

您可以使用类似的方法UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)来确定方向,然后相应地使用尺寸。

但是,在方向更改期间,例如在UIViewController的

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 
                                 duration:(NSTimeInterval)duration

使用传入的方向,toInterfaceOrientation因为UIApplication的statusBarOrientation仍会指向旧的方向,因为它尚未更改(因为您位于will事件处理程序中)。

摘要

有几个与此相关的帖子,但是每个帖子似乎都表明您必须:

  1. 看一下[[UIScreen mainScreen] bounds]尺寸,
  2. 检查您所处的方向,然后
  3. 考虑状态栏的高度(如果显示)

链接

工作守则

我通常不会走那么远,但是您激起了我的兴趣。以下代码可以解决问题。我在UIApplication上写了一个Category。我添加了类方法来获取currentSize或给定方向的大小,这就是您在UIViewController中调用的方法willRotateToInterfaceOrientation:duration:

@interface UIApplication (AppDimensions)
+(CGSize) currentSize;
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation;
@end

@implementation UIApplication (AppDimensions)

+(CGSize) currentSize
{
    return [UIApplication sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
}

+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
    CGSize size = [UIScreen mainScreen].bounds.size;
    UIApplication *application = [UIApplication sharedApplication];
    if (UIInterfaceOrientationIsLandscape(orientation))
    {
        size = CGSizeMake(size.height, size.width);
    }
    if (application.statusBarHidden == NO)
    {
        size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
    }
    return size;
}

@end

要使用代码简单调用[UIApplication currentSize]。另外,我运行了上面的代码,因此我知道它可以工作并向各个方向报告正确的响应。请注意,我考虑了状态栏。有趣的是,我必须减去状态栏的高度和宽度的最小值。

希望这可以帮助。:D

其他想法

您可以通过查看UIWindow的rootViewController属性来获取尺寸。我过去已经看过了,它在纵向和横向上都报告了相同的尺寸,只是报告了旋转变换:

(gdb) po [[[[[UIApplication sharedApplication] keyWindow] rootViewController]视图]

<UILayoutContainerView:0xf7296f0; 帧=(0 0; 320480); 变换= [0,-1,1,0,0,0]; 自动调整大小= W + H; 层= <CALayer:0xf729b80 >>

(gdb) po [[[[[UIApplication sharedApplication] keyWindow] rootViewController]视图]

<UILayoutContainerView:0xf7296f0; 帧=(0 0; 320480); 自动调整大小= W + H; 层= <CALayer:0xf729b80 >>

不确定应用程序的工作方式,但是如果您不使用某种导航控制器,则可以在主视图下有一个UIView,其父级的最大高度/宽度和父级的增大/缩小。然后,您可以这样做:[[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]。一方面看起来很激烈,但是您明白了。

但是...在摘要下执行上述3个步骤仍然更好。开始弄乱UIWindows,您会发现奇怪的东西,例如显示UIAlertView将更改UIApplication的键窗口,使其指向该UIAlertView创建的新UIWindow。谁知道?我发现了一个依赖keyWindow的错误并发现它像那样改变后才做了!


5
这似乎是一项基本任务,我很难相信自己必须破解自己的代码才能确定类似的内容。
MusiGenesis 2011年

2
我将尝试其他解决方案,如果可行,请重新发布。如果您不迅速回答,那么这个网站太激进了,您可能根本不回答。哈哈...:DI希望我的回答至少有帮助。同样,我会尽快尝试其他方法。
山姆

1
大!(顺便说一句,有人引起了我的兴趣):-)
Vamos 2012年

1
如果使用applicationFrame代替bounds(在UIScreen上),则不必减去状态栏的高度。
aopsfan 2013年

2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size已从iOS 8开始依赖方向
杰拉尔德

39

这是我的解决方案代码!此方法可以添加到NSObject类的Categroy中,或者您可以定义Top自定义UIViewController类,并让所有其他UIViewControllers继承它。

-(CGRect)currentScreenBoundsDependOnOrientation
{  

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
    }
    return screenBounds ;
}

请注意,在IOS8之后,正如UIScreen的bounds属性的Apple Document所述

讨论区

在当前坐标空间中指定了该矩形,该矩形考虑了对设备有效的任何接口旋转。因此,当设备在纵向和横向之间旋转时,此属性的值可能会更改。

因此,出于兼容性考虑,我们应该检测IOS版本并进行如下更改:

#define IsIOS8 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)

-(CGRect)currentScreenBoundsDependOnOrientation
{  

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    if(IsIOS8){
        return screenBounds ;
    }
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
    }
    return screenBounds ;
}

与我的答案大致相同,唯一遗漏的是“人像倒置”状态。这仅在您支持该方向时才重要。
罗伯特·瓦格斯塔夫

2
@Monjer不应命名不执行GET请求的方法,而将i前缀为get。currentScreenBoundsDependOnOrientation是该方法的更好称呼
bogen

1
@ Hakonbogen.yes可能是对的,因为“ peroperty”声明会自动生成setter / getter方法,这可能会导致命名冲突,并违反objc的命名约定。谢谢您的建议。
2013年

令人高兴的是,Apple 终于默认了他们的旋转代码完全是一团糟,并且刚刚开始告诉我们当前方向上该死的尺寸是多少。太糟糕了,直到第8版才到达那里。
MusiGenesis

30

这是一个方便的宏:

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

14

在iOS 8+中,您应该使用以下viewWillTransitionToSize:withTransitionCoordinator方法:

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // You can store size in an instance variable for later
    currentSize = size;

    // This is basically an animation block
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Get the new orientation if you want
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

        // Adjust your views
        [self.myView setFrame:CGRectMake(0, 0, size.width, size.height)];

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        // Anything else you need to do at the end
    }];
}

这将替换不推荐使用的动画方法,该方法不提供有关大小的信息:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration

这应该是公认的答案。现代而最新。
SarpErdag 2015年

对于iOS 8及更高版本,请使用此答案。
iPhoneDeveloper

10

从iOS 8开始,现在针对当前方向正确返回了屏幕边界。这意味着iPad处于横向[UIScreen mainScreen]。绑定在iOS <= 7上将返回768,在iOS 8上将返回1024。

以下代码在所有发行的版本上返回正确的高度和宽度。

-(CGRect)currentScreenBoundsDependOnOrientation
{
    NSString *reqSysVer = @"8.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
        return [UIScreen mainScreen].bounds;

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
        NSLog(@"Portrait Height: %f", screenBounds.size.height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
        NSLog(@"Landscape Height: %f", screenBounds.size.height);
    }

    return screenBounds ;
}

8

如果需要方向依赖的大小并且有视图,则可以使用:

view.bounds.size

大!KISS解决方案=保持简单和愚蠢
bsorrentino

3
KISS并不意味着“保持简单而愚蠢” –大声笑!意思是“保持简单,愚蠢!” :-)
Erik van der Neut 2014年

同样,该答案显然仅在已知您的视图完全为全屏的情况下才有效。但是,如果是这种情况,那么您可能没有OP最初发布的问题。
Erik van der Neut 2014年

5

我为编写了类别UIScreen,该类别适用于所有iOS版本,因此您可以像这样使用它:
[[UIScreen mainScreen] currentScreenSize]

@implementation UIScreen (ScreenSize)

- (CGSize)currentScreenSize {
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    CGSize screenSize = screenBounds.size;

    if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {  
        UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if ( UIInterfaceOrientationIsLandscape(interfaceOrientation) ) {
            screenSize = CGSizeMake(screenSize.height, screenSize.width);
        }
    }

    return screenSize;
}

@end

1
这对我来说似乎是最干净的答案。投票赞成。
Erik van der Neut 2014年

5

这是一种获取与方向相关的屏幕尺寸的快捷方法:

var screenWidth: CGFloat {
    if UIInterfaceOrientationIsPortrait(screenOrientation) {
        return UIScreen.mainScreen().bounds.size.width
    } else {
        return UIScreen.mainScreen().bounds.size.height
    }
}
var screenHeight: CGFloat {
    if UIInterfaceOrientationIsPortrait(screenOrientation) {
        return UIScreen.mainScreen().bounds.size.height
    } else {
        return UIScreen.mainScreen().bounds.size.width
    }
}
var screenOrientation: UIInterfaceOrientation {
    return UIApplication.sharedApplication().statusBarOrientation
}

这些作为我的项目中的标准功能包括在内:

https://github.com/goktugyil/EZSwiftExtensions


0
float msWidth = [[UIScreen mainScreen] bounds].size.width*(IS_RETINA?2.0f:1.0f);
float msHeight = [[UIScreen mainScreen] bounds].size.height*(IS_RETINA?2.0f:1.0f);
if ( UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ) {
    os->setWidth(MIN(msWidth, msHeight));
    os->setHeight(MAX(msWidth, msHeight));
} else {
    os->setWidth(MAX(msWidth, msHeight));
    os->setHeight(MIN(msWidth, msHeight));
}

NSLog(@"screen_w %f", os->getWidth());
NSLog(@"screen_h %f", os->getHeight());

0

但是,在iOS 8.0.2中:

+ (NSUInteger)currentWindowWidth
{
    NSInteger width = 0;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    CGSize size = [UIScreen mainScreen].bounds.size;
   // if (UIInterfaceOrientationIsLandscape(orientation)) {
   //     width = size.height;
   // } else {
        width = size.width;
  //  }

    return width;
}

0

对要调整大小的视图使用-> setNeedsDisplay()。

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.