画面の向きに依存する高さと幅を取得するにはどうすればよいですか?


96

アプリケーションの現在の高さと幅をプログラムで決定しようとしています。私はこれを使います:

CGRect screenRect = [[UIScreen mainScreen] bounds];

ただし、デバイスの向きが縦向きか横向きかに関係なく、幅320と高さ480になります。メイン画面の現在の幅と高さ(つまり、デバイスの向きに依存)を確認するにはどうすればよいですか?

回答:


164

のようなものUIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)を使用して方向を決定し、それに応じて寸法を使用できます。

ただし、UIViewControllerのような方向変更中

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

toInterfaceOrientationUIApplicationの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]。また、上記のコードを実行したので、それが機能し、すべての方向で正しい応答を報告します。ステータスバーを考慮することに注意してください。興味深いことに、ステータスバーの高さと幅のMINを引く必要がありました。

お役に立てれば。:D

他の考え

UIWindowのrootViewControllerプロパティを確認することで、寸法を取得できます。私は過去にこれを見てきましたが、回転変換があることを報告することを除いて、縦と横の両方で同じ寸法を同様に報告します:

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

<UILayoutContainerView:0xf7296f0; フレーム=(0 0; 320 480); 変換= [0、-1、1、0、0、0]; 自動サイズ変更= W + H; レイヤー= <CALayer:0xf729b80 >>

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

<UILayoutContainerView:0xf7296f0; フレーム=(0 0; 320 480); 自動サイズ変更= 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

1
applicationFrame代わりにbounds(UIScreen上で)を使用する場合は、ステータスバーの高さを減算する必要はありません。
aopsfan 2013年

2
stackoverflow.com/questions/24150359/… mainScreen().bounds.sizeは、iOS 8以降の方向に依存するようになりました
ジェラルド

39

これが私のソリューションコードです!このメソッドはNSObjectクラスのCategroyに追加できます。または、トップカスタム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プロパティのアップルドキュメントは言います:

討論

この長方形は現在の座標空間で指定され、デバイスに有効なインターフェースの回転を考慮に入れます。したがって、デバイスが縦向きと横向きの間で回転すると、このプロパティの値が変わる可能性があります。

互換性を考慮して、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 ;
}

私の答えとほとんど同じですが、それが見逃しているのは、それが逆さまの縦向きの場合だけです。これは、その方向性をサポートする場合にのみ重要です。
Robert Wagstaff 2013

2
@Monjerでは、GETリクエストを実行しないメソッドに名前を付けないでください。currentScreenBoundsDependOnOrientationは、メソッドのより適切な名前です
bogen

1
「peroperty」宣言が自動的にsetter / getterメソッドを生成するため、@ Hakonbogen.yesは正しいかもしれません。これにより、名前の競合が発生し、objcの命名規則に反する可能性があります。アドバイスありがとうございます。
monjer 2013年

Appleが彼らの回転コードが完全に混乱していることをついに暗黙のうちに認め、そして現在の方向におけるいまいましい次元が何であるかを私たちに伝え始めたのは素晴らしいことです。そこに到達するのにバージョン8までかかりました。
MusiGenesis 2014

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

この回答はiOS 8以降で使用します。
iPhoneDeveloper

10

iOS 8以降、画面の境界は現在の向きに対して正しく返されるようになりました。これは、iPadが横向き[UIScreen mainScreen] .boundsの場合、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 '16

3
KISSは、「Keep it Simple and Stupid」を意味するものではありません-LOL!それは「シンプルに、バカにしてください!」という意味です。:-)
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

以下は、向きに依存する画面サイズを取得する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


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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.