[UIScreen mainScreen] .bounds.sizeはiOS8で向きに依存しますか?


184

iOS 7とiOS 8の両方で次のコードを実行しました。

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
BOOL landscape = (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight);
NSLog(@"Currently landscape: %@, width: %.2f, height: %.2f", 
      (landscape ? @"Yes" : @"No"), 
      [[UIScreen mainScreen] bounds].size.width, 
      [[UIScreen mainScreen] bounds].size.height);

以下は、iOS 8からの結果です。

Currently landscape: No, width: 320.00, height: 568.00
Currently landscape: Yes, width: 568.00, height: 320.00

iOS 7の結果との比較:

Currently landscape: No, width: 320.00, height: 568.00
Currently landscape: Yes, width: 320.00, height: 568.00

この変更を指定するドキュメントはありますか?それともiOS 8 APIの一時的なバグですか?


13
まあiOS8の出力はもっと理にかなっているようだ
Levi

回答:


173

はい、iOS8では方向に依存しており、バグではありません。詳細については、WWDC 2014のセッション214を確認してください:「iOS 8でのビューコントローラーの進歩」

プレゼンテーションからの引用:

UIScreenはインターフェース指向になりました:

  • [UIScreen境界]インターフェース指向になりました
  • [UIScreen applicationFrame]がインターフェイス指向になりました
  • ステータスバーフレーム通知はインターフェイス指向です
  • キーボードフレーム通知はインターフェイス指向です

7
上記のWWDCの講義では、インターフェース指向の部分は51:50から始まります。
cnotethegr8 2014年

2
今日のほとんどは、この進歩を回避するために費やしてきました。どうやらそうではない常にそうので、他のアプリケーションで動作する必要があるSDKの開発者であれば、これはさらに複雑になります。
Glenn Maynard 2014

1
@arothあなたはいくつかの古い習慣にブレーキをかけることなく革新することはできません。
Boris Y.

23
@borisy-私は敬意を払いません。ほとんどの場合、下位互換性を維持しながら革新することが可能です。私の意見では、ブレイキングは何よりも怠惰の変化を変えます。彼らは他の誰もがその仕事をすることを望んでいる。
roth

1
この回答は、インターフェイス指向が実際に何を意味するかが説明されている場合、さらに役立ちます。私は間違っているかもしれませんが、方向依存はビューコントローラにのみ関係すると思います。他のクラスを使用して境界を計算しても、それらは依然として古いスタイルに従っており、常に縦長です。
マキシムス

59

はい、iOS8では方向依存です。

古いバージョンのOSをサポートする必要があるアプリでこの問題を解決するためのUtilメソッドを作成しました。

+ (CGSize)screenSize {
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        return CGSizeMake(screenSize.height, screenSize.width);
    }
    return screenSize;
}

1
コードを編集して確認してください。OSのバージョンをチェックする条件が間違っていました
Jageen

@Jageen明確にしてください、バージョンチェックは私にとってはうまくいきます。何が問題ですか?
cbartel 2014

私が理解していることは、OSがiOS8で向きが横の場合、高さと幅を変更する必要があるということです。
Jageen、2014

@Jageen Negative、iOS 8ではメソッドは向きに依存します。ロジックが切り替わります。編集は正しく拒否されました。
cbartel 2014

@cbartelは、これをUIScreenに分類して、[UIScreen mainScreen] .bounds.sizeへの最初の呼び出しがiOS 7とiOS 8の両方で機能するようにする方法はありますか?
kevinl 2014

34

はい、確かに、iOS 8では画面サイズが向きに依存するようになりました。ただし、サイズを縦向きに固定したい場合があります。これが私のやり方です。

+ (CGRect)screenBoundsFixedToPortraitOrientation {
    UIScreen *screen = [UIScreen mainScreen];

    if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) {
                    return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace];
    } 
    return screen.bounds;
}

2
これにより、通常のiPhoneアプリの問題は修正されますが、iPadで実行されているiPhoneアプリの問題は修正されません。
ThomasW 2014

32

はい、向きに依存しています。

上記の答えのいくつかよりも向きに依存しない方法で画面サイズを取得する以下の方法の方が簡単です。どちらもシンプルであり、向きコードのいずれにも依存しないためです(その状態は、それらが呼び出されたとき)またはバージョンチェック。新しいiOS 8の動作が必要な場合がありますが、これは、iOSのすべてのバージョンで安定させる必要がある場合に機能します。

+(CGSize)screenSizeOrientationIndependent {
     CGSize screenSize = [UIScreen mainScreen].bounds.size;
     return CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
}

おそらく、Apple TVのようなものでは機能しないでしょう。
cbh2000 2015年

11

私の問題を解決したこの質問に関連して、ここで私が画面の幅と高さの計算に使用する2つの定義:

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

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

#define IOS_VERSION_LOWER_THAN_8 (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)

iOS 7とiOS 8の両方をサポートしている場合、これがこの問題の最良の解決策です。


@Namit Gupta、あなたの編集は間違っています。IOSバージョンが8以上の場合、UIScreenの寸法は方向に依存するため、使用できます。iOS 8より前は、ステータスバーの向きを確認する必要がありました。あなたの編集は現在、8より下ではないすべてのiOSバージョンがstatusbarorientationをチェックする必要があると言っていますが、これは誤りです。
アントワーヌ

9

使用できますnativeBounds(向きに依存しません)

nativeBounds

ピクセル単位で測定された、物理画面の外接する四角形。(読み取り専用)

宣言SWIFT

  var nativeBounds: CGRect { get }

この長方形は、ポートレイトアップの向きのデバイスに基づいています。この値は、デバイスが回転しても変化しません。

デバイスの高さの検出:

if UIScreen.mainScreen().nativeBounds.height == 960.0 {

}

デバイスの幅の検出:

if UIScreen.mainScreen().nativeBounds.width == 640.0 {

}

3
このメソッドはピクセルを返しますが、他のほとんどのメソッドはポイントを処理することに注意してください。非常に異なるもの。
jcsahnwaldt Reinstate Monica、2015

1
私の場合、まさに私が必要とするもの:)(UIViewsに基づいていないが、正確なピクセル寸法を知る必要があるOpenGLまたは他のビュー)
Bersaelor

3
警告:iPhone 6以降では、これは1080 x 1920を返しましたが、これは期待したものではない可能性があります
Chanon

8

iOS 8 SDKのバグではありません。彼らは境界インターフェースの向きを依存させました。その事実へのいくつかの参照またはドキュメントについてのあなたの質問によると、私はView Controller Advancements in iOS 8それがWWDC 2014からの214セッションであることを見るように強くお勧めします。(あなたの疑問によると)最も興味深い部分Screen Coordinatesは50:45から始まります。


5

はい、iOS8では方向依存です。

SDKとOSのバージョン間でiOS 8の方法で境界を読み取る一貫した方法を以下に示します。

#ifndef NSFoundationVersionNumber_iOS_7_1
# define NSFoundationVersionNumber_iOS_7_1 1047.25
#endif

@implementation UIScreen (Legacy)

// iOS 8 way of returning bounds for all SDK's and OS-versions
- (CGRect)boundsRotatedWithStatusBar
{
    static BOOL isNotRotatedBySystem;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        BOOL OSIsBelowIOS8 = [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0;
        BOOL SDKIsBelowIOS8 = floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1;
        isNotRotatedBySystem = OSIsBelowIOS8 || SDKIsBelowIOS8;
    });

    BOOL needsToRotate = isNotRotatedBySystem && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);
    if(needsToRotate)
    {
        CGRect screenBounds = [self bounds];
        CGRect bounds = screenBounds;
        bounds.size.width = screenBounds.size.height;
        bounds.size.height = screenBounds.size.width;
        return bounds;
    }
    else
    {
        return [self bounds];
    }
}

@end

1
同僚が異なるバージョンのSDKを使用してアプリを構築している場合に備えて、SDKのバージョンも確認することをお勧めします(これは発生しないはずです!)。
クレイグマクマホン

4

私の解決策は、MaxKとhfossliの組み合わせです。UIScreenのカテゴリでこのメソッドを作成しましたが、バージョンチェックがありません(これは悪い習慣です)。

//Always return the iOS8 way - i.e. height is the real orientation dependent height
+ (CGRect)screenBoundsOrientationDependent {
    UIScreen *screen = [UIScreen mainScreen];
    CGRect screenRect;
    if (![screen respondsToSelector:@selector(fixedCoordinateSpace)] && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        screenRect = CGRectMake(screen.bounds.origin.x, screen.bounds.origin.y, screen.bounds.size.height, screen.bounds.size.width);
    } else {
        screenRect = screen.bounds;
    }

    return screenRect;
}

3

iOS8でiOS7と同じ動作を維持するクイックヘルパー関数が必要でした。これにより、[[UIScreen mainScreen] bounds]呼び出しを入れ替えて他のコードに触れないようにすることができました...

+ (CGRect)iOS7StyleScreenBounds {
    CGRect bounds = [UIScreen mainScreen].bounds;
    if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        bounds.size = CGSizeMake(bounds.size.height, bounds.size.width);
    }
        return bounds;
}

厄介ですが、適切に修正できるようになるまで時間が
かかり

3

以下のメソッドを使用して、iOSバージョンに関係なく、特定の方向の画面境界を見つけることができます。このメソッドは、デバイスの画面サイズに基づいて境界を返し、iOSバージョンに関係なく同じCGRect値を提供します。

- (CGRect)boundsForOrientation:(UIInterfaceOrientation)orientation {

    CGFloat width   = [[UIScreen mainScreen] bounds].size.width;
    CGFloat height  = [[UIScreen mainScreen] bounds].size.height;

    CGRect bounds = CGRectZero;

    if (UIInterfaceOrientationIsLandscape(orientation)) {
        bounds.size = CGSizeMake(MAX(width, height), MIN(width, height));
    } else {
        bounds.size = CGSizeMake(MIN(width, height), MAX(width, height));
    }

    return bounds;
}

// For the below example, bounds will have the same value if you run the code on iOS 8.x or below versions.
CGRect bounds = [self boundsForOrientation:UIInterfaceOrientationPortrait]; 

1

それは私が正しい長方形を計算するために使用したものです:

UIScreen* const mainScreen = [UIScreen mainScreen];
CGRect rect = [mainScreen bounds];
#ifdef __IPHONE_8_0
if ([mainScreen respondsToSelector:@selector(coordinateSpace)])
{
    if ([mainScreen respondsToSelector:@selector(fixedCoordinateSpace)])
    {
        id tmpCoordSpace = [mainScreen coordinateSpace];
        id tmpFixedCoordSpace = [mainScreen fixedCoordinateSpace];

        if ([tmpCoordSpace respondsToSelector:@selector(convertRect:toCoordinateSpace:)])
        {
            rect = [tmpCoordSpace convertRect:rect toCoordinateSpace: tmpFixedCoordSpace];
        }
    }
}
#endif

1

上で答えた優れたcbartel関数のSwiftバージョンを追加するだけです。

func screenSize() -> CGSize {
    let screenSize = UIScreen.mainScreen().bounds.size
    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) && UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
        return CGSizeMake(screenSize.height, screenSize.width)
    }
    return screenSize
}

1

私の問題はマイナスになっていたUIWindowsフレームに関連していた。MyViewController-(NSUInteger)supportedInterfaceOrientationsメソッドで以下のようにコードを作成しました

[[UIApplication sharedApplication] setStatusBarHidden:NO];

[self.view setFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];

[appDel.window setFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];

そして、私の仕事はそれを試してみます。


1

iOS 8以降

ポイントで画面サイズを知りたい人のための解決策(3.5インチ画面には320×480ポイント、4.0インチ画面には320×568ポイントなど)があります。

- (CGSize)screenSizeInPoints
{
    CGFloat width = [[UIScreen mainScreen] bounds].size.width;
    CGFloat height = [[UIScreen mainScreen] bounds].size.height;

    if (width > height) {
        return CGSizeMake(height, width);
    }
    else {
        return [[UIScreen mainScreen] bounds].size;
    }
}

0

私が気づいたことの一つは、順序です Info.plistでサポートされるインターフェイスの向きのが重要であることです。私のアプリ(コードで方向付けを行う)でこの質問の問題が発生しましたが、デフォルトの方向が縦向きであると指定していません。

デフォルトの向きポートレート。

Info.plistでitensを再配置し、Portraitを最初にすると、予期した動作が復元されました。


0

これにより、iOS7iOS8の両方で正しいデバイスが得られます。

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define IS_PORTRAIT         UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)

+ (BOOL)isIPHONE4{

// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){

        if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 480.0) {
            return YES;
        } else {
            return NO;
        }

// >= iOS 8.0
}else{

    if(IS_PORTRAIT){

        if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 480.0) {
            return YES;
        } else {
            return NO;
        }

    }else{

        if ([self getDeviceWidth] == 480.0 && [self getDeviceHeight] == 320.0) {
            return YES;
        } else {
            return NO;
        }

    }

}


}

+ (BOOL)isIPHONE5{


// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){

    if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 568.0) {
        return YES;
    } else {
        return NO;
    }

    // >= iOS 8.0
}else{

    if(IS_PORTRAIT){

        if ([self getDeviceWidth] == 320.0 && [self getDeviceHeight] == 568.0) {
            return YES;
        } else {
            return NO;
        }

    }else{

        if ([self getDeviceWidth] == 568.0 && [self getDeviceHeight] == 320.0) {
            return YES;
        } else {
            return NO;
        }

    }

}

}

+ (BOOL)isIPHONE6{

// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){

    if ([self getDeviceWidth] == 375.0 && [self getDeviceHeight] == 667.0) {
        return YES;
    } else {
        return NO;
    }

    // >= iOS 8.0
}else{

    if(IS_PORTRAIT){

        if ([self getDeviceWidth] == 375.0 && [self getDeviceHeight] == 667.0) {
            return YES;
        } else {
            return NO;
        }

    }else{

        if ([self getDeviceWidth] == 667.0 && [self getDeviceHeight] == 375.0) {
            return YES;
        } else {
            return NO;
        }

    }

}


}
+ (BOOL)isIPHONE6Plus{


// < iOS 8.0
if(SYSTEM_VERSION_LESS_THAN(@"8.0")){

    if ([self getDeviceWidth] == 414.0 && [self getDeviceHeight] == 736.0) {
        return YES;
    } else {
        return NO;
    }

    // >= iOS 8.0
}else{

    if(IS_PORTRAIT){

        if ([self getDeviceWidth] == 414.0 && [self getDeviceHeight] == 736.0) {
            return YES;
        } else {
            return NO;
        }

    }else{

        if ([self getDeviceWidth] == 736.0 && [self getDeviceHeight] == 414.0) {
            return YES;
        } else {
            return NO;
        }

    }

}


}

+ (CGFloat)getDeviceHeight{

//NSLog(@"Device width: %f",[UIScreen mainScreen].bounds.size.height);
return [UIScreen mainScreen].bounds.size.height;
}
+ (CGFloat)getDeviceWidth{

//NSLog(@"Device width: %f",[UIScreen mainScreen].bounds.size.height);
return [UIScreen mainScreen].bounds.size.width;
}

//デバイスを追加することもできます(ieiPad)。


質問は、画面解像度に基づくデバイスの認識に関するものではありません。さらに、Appleは、デバイス/画面の検出ではなくサイズクラスに基づくアダプティブUIを作成することを推奨しています
JulianKrólAug

0

わずかに変更されたmnemiaのソリューションを使用しました。これは、iOSバージョンのチェックなしで、メイン画面の境界で最小/最大を使用します。
私はメイン画面の境界からCGRect取得CGRectしたものを必要として変更size.width=min(w,h)しましたsize.height=max(w,h)。次に、OSに依存しないget CGRect関数をコードの2か所で呼び出しました。ここでOpenGLは、、タッチなどの画面サイズを取得しています。修正前に、2つの問題がありました-横長モードのIOS 8.xで、OpenGLビューの表示位置が正しくありませんでした:1 /左下部分にフルスクリーンの4。また、2回目のタッチで無効な値が返されました。説明のとおり、両方の問題が修正されました。ありがとう!

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