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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7905432/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:04:19  来源:igfitidea点击:

How to get orientation-dependent height and width of the screen?

ios

提问by MusiGenesis

I'm trying to programmatically determine the current height and width of my application. I use this:

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

CGRect screenRect = [[UIScreen mainScreen] bounds];

But this yields a width of 320 and a height of 480, regardless of whether the device is in portrait or landscape orientation. How can I determine the currentwidth and height (i.e. dependent upon the device orientation) of my main screen?

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

回答by Sam

You can use something like UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)to determine the orientation and then use the dimensions accordingly.

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

HOWEVER, during an orientation change like in UIViewController's

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

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

Use the orientation passed in toInterfaceOrientationsince the UIApplication's statusBarOrientation will still point to the old orientation as it has not yet changed (since you're inside a willevent handler).

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

Summary

概括

There are several related posts to this, but each of them seem to indicate that you have to:

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

  1. Look at [[UIScreen mainScreen] bounds]to get the dimensions,
  2. Check what orientation you are in, and
  3. Account for the status bar height (if shown)
  1. 查看[[UIScreen mainScreen] bounds]以获取尺寸,
  2. 检查您所处的方向,以及
  3. 考虑状态栏高度(如果显示)

Links

链接

Working Code

工作代码

I usually don't go this far, but you piqued my interest. The following code should do the trick. I wrote a Category on UIApplication. I added class methods for getting the currentSize or the size in a given orientation, which is what you would call in UIViewController's willRotateToInterfaceOrientation:duration:.

我通常不会走这么远,但你激起了我的兴趣。以下代码应该可以解决问题。我在 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

To use the code simple call [UIApplication currentSize]. Also, I ran the above code, so I know it works and reports back the correct responses in all orientations. Note that I factor in the status bar. Interestingly I had to subtract the MIN of the status bar's height and width.

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

Hope this helps. :D

希望这可以帮助。:D

Other thoughts

其他想法

You could go about getting the dimensions by looking at the UIWindow's rootViewControllerproperty. I've looked at this in the past and it similarly reports the same dimensions in both portrait and landscape except it reports having a rotate transform:

您可以通过查看 UIWindow 的rootViewController属性来获取尺寸。我过去看过这个,它类似地报告了纵向和横向的相同尺寸,只是它报告了旋转变换:

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

<UILayoutContainerView: 0xf7296f0; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0xf729b80>>

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

<UILayoutContainerView: 0xf7296f0; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0xf729b80>>

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

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

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

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

Not sure how your app works, but if you aren't using a navigation controller of some kind, you could have a UIView under your main view with the max height / width of parent and grows / shrinks with parent. Then you could do: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]. That looks pretty intense on one line, but you get the idea.

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

However... It would still be better to do the above 3 steps under the summary. Start messing with UIWindows and you'll find out weird stuff, like showing a UIAlertView will change UIApplication's keywindow to point at a new UIWindow that the UIAlertView created. Who knew? I did after finding a bug relying on keyWindow and discovering that it changed like that!

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

回答by monjer

This is my solution code !This method can add to NSObject class's Categroy , or you can define a Top custom UIViewController class , and let all of your other UIViewControllers to inherit it .

这是我的解决方案代码!这个方法可以添加到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 ;
}

Note, after IOS8 , as Apple Document of UIScreen's bounds propertysays :

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

Discussion

This rectangle is specified in the current coordinate space, which takes into account any interface rotations in effect for the device. Therefore, the value of this property may change when the device rotates between portrait and landscape orientations.

讨论

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

so for the consideration of compatibility , we should detect the IOS version and make the change as below:

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

回答by Robert Wagstaff

Here's a handy macro:

这是一个方便的宏:

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

回答by Mark Hennings

In iOS 8+ you should use the viewWillTransitionToSize:withTransitionCoordinatormethod:

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

This replaces the deprecated animation method that gave no information about size:

这取代了不推荐使用的动画方法,该方法不提供有关大小的信息:

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

回答by A.Badger

As of iOS 8 screen bounds are now returned correct for current orientation. This means an iPad in landscape orientation [UIScreen mainScreen].bounds would return 768 on iOS <=7 and 1024 on iOS 8.

从 iOS 8 开始,屏幕边界现在返回正确的当前方向。这意味着横向的 iPad [UIScreen mainScreen].bounds 在 iOS <=7 上将返回 768,在 iOS 8 上返回 1024。

The following returns the correct height and width on all versions released.

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

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

回答by Tod

if you want the orientation dependent size and you have a view, you can just use:

如果你想要依赖于方向的大小并且你有一个视图,你可以使用:

view.bounds.size

回答by ArtFeel

I wrote category for UIScreen, that works on all iOS versions, so you can use it like this:
[[UIScreen mainScreen] currentScreenSize].

我写的类别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

回答by Esqarrouth

Here is a Swift way to get orientation dependent screen sizes:

这是获取与方向相关的屏幕尺寸的 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
}

These are included as a standard function in a project of mine:

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

https://github.com/goktugyil/EZSwiftExtensions

https://github.com/goktugyil/EZSwiftExtensions

回答by Santosh

use -> setNeedsDisplay() for the view you want to resize.

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

回答by user4082558

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