【问题标题】:How to get orientation-dependent height and width of the screen?如何获得与方向相关的屏幕高度和宽度?
【发布时间】:2023-03-11 21:11:01
【问题描述】:

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

CGRect screenRect = [[UIScreen mainScreen] bounds];

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

【问题讨论】:

    标签: ios


    【解决方案1】:

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

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

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

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

    总结

    有几个相关的帖子,但每个帖子似乎都表明你必须:

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

    链接

    工作代码

    我通常不会走这么远,但你激起了我的兴趣。下面的代码应该可以解决问题。我在 UIApplication 上写了一个类别。我添加了类方法来获取给定方向的 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] 视图]

    >

    (gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] view]

    >

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

    不过……还是按照总结下的3个步骤来做比较好。开始弄乱 UIWindows,你会发现奇怪的东西,比如显示 UIAlertView 会改变 UIApplication 的 keywindow 以指向 UIAlertView 创建的新 UIWindow。谁知道?在发现一个依赖于 keyWindow 的错误并发现它发生了这样的变化后,我做到了!

    【讨论】:

    • 这似乎是一项非常基本的任务,以至于我无法相信我必须破解自己的代码才能确定这样的事情。
    • 我会尝试另一种解决方案,如果可行,我会重新发布。这个网站太激进了,如果你不快速回答,你可能根本不回答。哈哈... :D 我希望我的回答至少有帮助。再说一次,我会尽快尝试其他方法。
    • 太棒了! (顺便说一句,一个人的兴趣被激起了):-)
    • 如果您使用applicationFrame 而不是bounds(在 UIScreen 上),则不必减去状态栏高度。
    • stackoverflow.com/questions/24150359/… mainScreen().bounds.size 从 iOS 8 开始变得依赖于方向
    【解决方案2】:

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

    -(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 之后,正如Apple Document of UIScreen's bounds property 所说:

    讨论

    此矩形在当前坐标空间中指定,其中考虑了对设备有效的任何界面旋转。因此,当设备在纵向和横向之间旋转时,此属性的值可能会发生变化。

    所以出于兼容性的考虑,我们应该检测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 ;
    }
    

    【讨论】:

    • 与我的答案几乎相同,唯一错过的是它是否在纵向颠倒。仅当您支持该方向时,这才有意义。
    • @Monjer 您不应命名不执行 GET 请求的方法,并在 i 前加上 get 一词。 currentScreenBoundsDependOnOrientation 是该方法的更好名称
    • @Hakonbogen.yes 可能你是对的,因为“peroperty”声明会自动生成 setter/getter 方法,这可能会导致命名冲突,并违反 objc 的命名约定。感谢您的建议。
    • 很高兴Apple终于默认他们的旋转代码完全是一团糟,并刚刚开始告诉我们当前方向的该死尺寸是多少。太糟糕了,直到版本 8 才到达那里。
    【解决方案3】:

    这是一个方便的宏:

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

    【讨论】:

      【解决方案4】:

      在 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
      

      【讨论】:

      • 这应该是公认的答案。现代和最新的。
      • 将此答案用于 ios 8 及更高版本。
      【解决方案5】:

      从 iOS 8 开始,现在可以正确返回当前方向的屏幕边界。这意味着横向的 iPad [UIScreen mainScreen].bounds 在 iOS

      以下内容返回所有已发布版本的正确高度和宽度。

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

      【讨论】:

        【解决方案6】:

        如果你想要与方向相关的大小并且你有一个视图,你可以使用:

        view.bounds.size
        

        【讨论】:

        • 太棒了! KISS 解决方案 = 保持简单和愚蠢
        • KISS 并不意味着“保持简单和愚蠢”——哈哈!这意味着“保持简单,愚蠢!” :-)
        • 另外,这个答案显然只有在你的视图被认为是完全全屏的情况下才有效。但是,如果是这种情况,那么您可能没有 OP 发布的原始问题。
        【解决方案7】:

        我为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
        

        【讨论】:

        • 这对我来说似乎是最干净的答案。投票赞成。
        【解决方案8】:

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

        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

        【讨论】:

          【解决方案9】:
          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());
          

          【讨论】:

            【解决方案10】:

            但是,在 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;
            }
            

            【讨论】:

              【解决方案11】:

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

              【讨论】:

                【解决方案12】:

                在 Swift 中对此处提供的答案进行了一些改进:

                    let interfaceOrientation = UIApplication.shared.statusBarOrientation // (< iOS 13)
                    let screenSize = UIScreen.main.bounds.size
                    let screenWidth = interfaceOrientation.isPortrait ? screenSize.width : screenSize.height
                    let screenHeight = interfaceOrientation.isPortrait ? screenSize.height : screenSize.width
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-09-25
                  • 2018-09-03
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-11-01
                  • 2011-09-09
                  • 1970-01-01
                  相关资源
                  最近更新 更多