如何在iOS中获取屏幕宽度和高度?

545

如何在 iOS 中获取屏幕的尺寸?

目前,我使用以下代码:

lCurrentWidth = self.view.frame.size.width;
lCurrentHeight = self.view.frame.size.height;

viewWillAppear:willAnimateRotationToInterfaceOrientation:duration: 方法中:

第一次获取整个屏幕大小。第二次获取的是屏幕减去导航栏的大小。


确保您的应用程序实际上是全屏的,而不是看到黑色条纹围绕它 - 如果是这样,那么这可能是您的解决方案 - bobobobo
自从苹果发布了带有刘海的设备以来,所有这些答案似乎都局限于这些设备上的安全区域。例如,在iPhone 14 Pro Max模拟器上,我从MainScreen和SharedApplication.Windows[0]中看到的高度为736(DIPs)。在3倍密度下,这相当于2208个像素。设备规格为2796个像素(相当于932个DIPs)。顶部和底部有大黑边。我还没有尝试调整故事板;我同意bobobobo的观点,目前的情况比这些旧答案更复杂。注意:从Xamarin.iOS调用。 - undefined
18个回答

1106

如何在iOS中获取屏幕的尺寸?

你所贴出的代码存在问题,因为你假设视图大小与屏幕大小相同,但实际情况并非总是如此。如果你需要屏幕大小,应该查看代表屏幕本身的对象,就像这样:

CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;

分屏视图的更新:Dmitry在评论中问道:

我该如何获取分屏视图中屏幕的大小?

上面提供的代码报告了屏幕的大小,即使在分屏模式下也是如此。当您使用分屏模式时,应用程序的窗口会发生变化。如果上面的代码没有给出您期望的信息,那么像原帖作者一样,您正在查看错误的对象。但在这种情况下,您应该查看窗口而不是屏幕,就像这样:

CGRect windowRect = self.view.window.frame;
CGFloat windowWidth = windowRect.size.width;
CGFloat windowHeight = windowRect.size.height;

Swift 4.2

let screenRect = UIScreen.main.bounds
let screenWidth = screenRect.size.width
let screenHeight = screenRect.size.height

// split screen            
let windowRect = self.view.window?.frame
let windowWidth = windowRect?.size.width
let windowHeight = windowRect?.size.height

7
方向控制实际上是在视图控制器层面进行管理的。请参阅管理视图控制器界面方向。所以,是的,请查看您的视图控制器的interfaceOrientation属性。顺便提一下,您询问了屏幕大小,所以我展示了给您,但是为了显示您的内容,您应该使用窗口的边界或屏幕的applicationFrame,具体取决于您正在做什么。 - Caleb
2
值得注意的是,这将返回没有填充的完整屏幕宽度。只需从这些结果中减去您应用程序的填充(通常每侧为20)即可获得大多数元素的“可用”空间。 - Nick Daugherty
2
@NickDaugherty 是的,这就是重点——OP想要屏幕尺寸。在屏幕上放置对象完全取决于您正在构建的应用程序类型。例如,如果您正在显示照片或游戏界面,则可能根本不需要填充。 - Caleb
5
请注意,这将返回一个以“点”为单位的值。因此,如果您期望屏幕分辨率以像素为单位,则结果将不正确,您应该将结果乘以[UIScreen scale] - Robotbugs
3
有人指出,由于a CGRect可以有负宽度或高度,我们应该使用CGRectGetWidth()CGRectGetHeight()而不是直接访问矩形的size字段。我认为这对于屏幕矩形来说可能永远不会成为问题,但是我想这也是需要注意的事情。 - Caleb
显示剩余11条评论

63

注意,[UIScreen mainScreen] 包含状态栏,如果你想要获取应用程序的框架(不包括状态栏),你应该使用

+ (CGFloat) window_height   {
    return [UIScreen mainScreen].applicationFrame.size.height;
}

+ (CGFloat) window_width   {
    return [UIScreen mainScreen].applicationFrame.size.width;
}

6
在iOS 9.0中已被弃用。 - Zakaria Darwish
8
由于应用程序框架(applicationFrame)已弃用,请替换为 return [[UIScreen mainScreen] bounds].size.width; - user5724570

48

我已经将一些上面的Objective-C答案翻译成了Swift代码。每个翻译前都有对原始答案的引用。

主要回答

let screen = UIScreen.main.bounds
let screenWidth = screen.size.width
let screenHeight = screen.size.height

##简单的函数回答

func windowHeight() -> CGFloat {
    return UIScreen.main.bounds.size.height
}

func windowWidth() -> CGFloat {
    return UIScreen.main.bounds.size.width
}

##设备方向解答

let screenHeight: CGFloat
let statusBarOrientation = UIApplication.shared.statusBarOrientation
// it is important to do this after presentModalViewController:animated:
if (statusBarOrientation != .portrait
    && statusBarOrientation != .portraitUpsideDown) {
    screenHeight = UIScreen.main.bounds.size.width
} else {
    screenHeight = UIScreen.main.bounds.size.height
}

##记录答案

let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
println("width: \(screenWidth)")
println("height: \(screenHeight)")

日志中似乎有一个错别字:应该是UIScreen.mainScreen().bounds.size.width吗?没有".bounds"会导致编译错误。 - stone
@skypecakes 我已经修复了答案,包括“.bounds”。感谢您的反馈。 - Martin Woolstenhulme
applicationFrame在iOS 9及以上版本中已被弃用,请使用return UIScreen.mainScreen().bounds].size.width进行替换。 - Suhaib

39

我以前使用过这些便捷方法:

- (CGRect)getScreenFrameForCurrentOrientation {
    return [self getScreenFrameForOrientation:[UIApplication sharedApplication].statusBarOrientation];
}

- (CGRect)getScreenFrameForOrientation:(UIInterfaceOrientation)orientation {

    CGRect fullScreenRect = [[UIScreen mainScreen] bounds];

    // implicitly in Portrait orientation.
    if (UIInterfaceOrientationIsLandscape(orientation)) {
      CGRect temp = CGRectZero;
      temp.size.width = fullScreenRect.size.height;
      temp.size.height = fullScreenRect.size.width;
      fullScreenRect = temp;
    }

    if (![[UIApplication sharedApplication] statusBarHidden]) {
      CGFloat statusBarHeight = 20; // Needs a better solution, FYI statusBarFrame reports wrong in some cases..
      fullScreenRect.size.height -= statusBarHeight;
    }

    return fullScreenRect;
} 

不错的解决方案,但要注意temp似乎没有定义的来源。 - szemian
4
默认情况下,您是否得到0,0?当我记录fullScreenRect时,它给了我:{{8.03294e-35,3.09816e-40},{480,320}}。我选择使用CGRectZero进行初始化。 - szemian
1
UIInterfaceOrientationIsLandscape无法处理从UIDevice返回的“UIDeviceOrientationFaceUp”和“UIDeviceOrientationFaceDown”。 - Andriy
6
你可以使用属性screen.applicationFrame而不是screen.bounds,该属性会考虑到状态栏的高度。 - Geraud.ch
在某些情况下,applicationFrame没有返回正确减去状态栏的框架(从分屏视图中全屏模态)。 - Luke Mcneice

15

我知道这是一篇旧文章,但有时候我会发现定义像这样的常量很有用,这样我就不必担心:

#define DEVICE_SIZE [[[[UIApplication sharedApplication] keyWindow] rootViewController].view convertRect:[[UIScreen mainScreen] bounds] fromView:nil].size

以上的常数应该能够在设备旋转时返回正确的尺寸。获取尺寸的过程就像这样简单:

lCurrentWidth = DEVICE_SIZE.width;
lCurrentHeight = DEVICE_SIZE.height;

你可能想要以AnswerBot的答案为基础来编写宏,因为那似乎是最好的答案。 - griotspeak

13

获取设备尺寸并考虑方向非常容易:

// grab the window frame and adjust it for orientation
UIView *rootView = [[[UIApplication sharedApplication] keyWindow] 
                                   rootViewController].view;
CGRect originalFrame = [[UIScreen mainScreen] bounds];
CGRect adjustedFrame = [rootView convertRect:originalFrame fromView:nil];

嗨,我在一个仅适用于iPad横屏的应用程序中使用了viewDidLoad。有没有什么原因导致它第一次获取正确的值,然后在每次加载后值会“翻转”,即它首先将其读取为横向视图,然后我导航离开并返回到该视图,它似乎将其读取为纵向视图,即使没有进行方向更改?谢谢。 - craigk
@LukeMcneice 在我的生产代码中,我有一个断言来确保找到一个框架...我还没有遇到过这个断言失败的情况。rootView和originalFrame返回了什么? - memmons
我正在使用单例模式中的这种技术来获取方向校正后的宽度/高度。然而,如果此代码在显示UIAlert窗口时运行,convertRect将返回一个大小为0(至少是宽度)的adjustedFrame。您有什么想法是怎么回事吗? - Electro-Bunny
啊,一个UIAlertView会将自己插入为keyWindow的rootViewController视图。我有一个逻辑来避免这种特殊情况,因为如果有一个警告视图弹出,用户就无法与键盘进行交互,所以通常不需要在那个时候获取键盘的框架。 - memmons
谢谢您的见解。我在横幅广告单例中使用了您的技术。这是一种简单而不错的方法,可以告诉广告API新广告的屏幕框架大小。由于我无法互斥地排除横幅广告和UIAlert,所以我可能会退而求其次,检测横向和纵向,并根据需要进行x/y轴的强制切换。 - Electro-Bunny

10

使用这些Structs来了解当前设备在Swift中的有用信息。

struct ScreenSize { // Answer to OP's question
    
    static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
    static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
    static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
    static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
    
}

struct DeviceType { //Use this to check what is the device kind you're working with
    
    static let IS_IPHONE_4_OR_LESS  = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH < 568.0
    static let IS_IPHONE_SE         = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 568.0
    static let IS_IPHONE_7          = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 667.0
    static let IS_IPHONE_7PLUS      = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 736.0
    static let IS_IPHONE_X          = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 812.0
    static let IS_IPAD              = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1024.0
    
}


struct iOSVersion { //Get current device's iOS version
    
    static let SYS_VERSION_FLOAT  = (UIDevice.current.systemVersion as NSString).floatValue
    static let iOS7               = (iOSVersion.SYS_VERSION_FLOAT >= 7.0 && iOSVersion.SYS_VERSION_FLOAT < 8.0)
    static let iOS8               = (iOSVersion.SYS_VERSION_FLOAT >= 8.0 && iOSVersion.SYS_VERSION_FLOAT < 9.0)
    static let iOS9               = (iOSVersion.SYS_VERSION_FLOAT >= 9.0 && iOSVersion.SYS_VERSION_FLOAT < 10.0)
    static let iOS10              = (iOSVersion.SYS_VERSION_FLOAT >= 10.0 && iOSVersion.SYS_VERSION_FLOAT < 11.0)
    static let iOS11              = (iOSVersion.SYS_VERSION_FLOAT >= 11.0 && iOSVersion.SYS_VERSION_FLOAT < 12.0)
    static let iOS12              = (iOSVersion.SYS_VERSION_FLOAT >= 12.0 && iOSVersion.SYS_VERSION_FLOAT < 13.0)
    static let iOS13              = (iOSVersion.SYS_VERSION_FLOAT >= 13.0 && iOSVersion.SYS_VERSION_FLOAT < 14.0)
    static let iOS14              = (iOSVersion.SYS_VERSION_FLOAT >= 14.0 && iOSVersion.SYS_VERSION_FLOAT < 15.0)
    static let iOS15              = (iOSVersion.SYS_VERSION_FLOAT >= 15.0 && iOSVersion.SYS_VERSION_FLOAT < 16.0)
    static let iOS16              = (iOSVersion.SYS_VERSION_FLOAT >= 16.0 && iOSVersion.SYS_VERSION_FLOAT < 17.0)
    
}

9
我们还需要考虑设备的方向:
CGFloat screenHeight;
// it is important to do this after presentModalViewController:animated:
if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortraitUpsideDown){
    screenHeight = [UIScreen mainScreen].applicationFrame.size.height;
}
else{
    screenHeight = [UIScreen mainScreen].applicationFrame.size.width;
}

好的解决方案。我这样做是为了让我的iPad应用程序在嵌入式视图控制器内以横向模式工作,当呈现模态VC时。 - StackRunner

8
NSLog(@"%.0f", [[UIScreen mainScreen] bounds].size.width);
NSLog(@"%.0f", [[UIScreen mainScreen] bounds].size.height);

6

我已经更新到 Swift 3

applicationFrame 在iOS 9中已经被弃用

在Swift 3中,他们移除了()并改变了一些命名约定,你可以参考这里链接

func windowHeight() -> CGFloat {
    return UIScreen.main.bounds.size.height
}

func windowWidth() -> CGFloat {
    return UIScreen.main.bounds.size.width
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接