iOS8에서 [UIScreen mainScreen] .bounds.size가 방향에 따라 달라 집니까?


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

2
나는 오늘이 발전을 해결하기 위해 대부분의 시간을 보냈다. 분명히하지 않습니다 항상 다른 응용 프로그램에서 작업에 필요,이 물건은 단지 더 복잡있어한다는 SDK의 개발자 그렇다면, 일.
Glenn Maynard

1
@aroth 오래된 habbits를 제동하지 않고는 혁신 할 수 없습니다.
보리스 Y.

23
@ borisy-나는 정중하게 동의하지 않습니다. 대부분의 경우 이전 버전과의 호환성을 유지하면서 혁신 할 수 있습니다. 내 생각에 변화를 깨는 것은 무엇보다도 게으름을 헤치고 나갔다. 그들은 모두가 그 일 을하기를 원합니다 .
aroth

1
이 답변은 인터페이스 지향이 실제로 무엇을 의미 하는지 설명하면 더 도움이 될 것 입니다. 틀릴 수도 있지만 방향 의존성은 컨트롤러를 보는 것에 만 관련이 있다고 생각합니다. 다른 클래스를 가져 와서 경계를 계산하면 여전히 오래된 스타일에 따라 항상 세로입니다.
Maxi Mus

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

내가 이해하는 것은 OS가 iOS8이고 방향이 가로이면 높이와 너비를 변경해야한다는 것입니다.
Jageen

@Jageen Negative, iOS 8에서는 방법이 방향에 따라 다릅니다. 당신의 논리가 바뀝니다. 편집이 올바르게 거부되었습니다.
cbartel

@cbartel은 이것을 UIScreen으로 분류하여 [UIScreen mainScreen] .bounds.size에 대한 원래 호출이 iOS 7과 iOS 8 모두에서 작동하도록 할 수 있습니까?
kevinl

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

32

예, 이제 방향에 따라 다릅니다.

위의 답변 중 일부가 방향과 무관하게 화면 크기를 얻는 방법을 선호합니다. 단순하고 방향 코드에 의존하지 않기 때문에 (상태는 호출 된 시간) 또는 버전 확인 중입니다. 새로운 iOS 8 동작을 원할 수도 있지만 모든 iOS 버전에서 안정적으로 작동해야하는 경우 작동합니다.

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

아마도 애플 TV와 같은 것에서는 작동하지 않을 것입니다.
cbh2000

11

내 문제를 해결 한이 질문과 관련하여 화면 너비 및 높이 계산에 사용하는 두 가지 정의가 있습니다.

#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 버전은 상태 표시 방향을 확인해야한다고 말하고 있습니다.
Antoine

9

사용할 수 있습니다 nativeBounds(방향 독립적)

nativeBounds

실제 화면의 경계 사각형으로 픽셀 단위로 측정됩니다. (읽기 전용)

선언 스위프트

  var nativeBounds: CGRect { get }

이 사각형은 세로 방향의 장치를 기준으로합니다. 장치가 회전해도이 값은 변경되지 않습니다.

장치 높이 감지 :

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

}

장치 너비 감지 :

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

}

3
이 방법은 픽셀을 반환하지만 대부분의 다른 방법은 점을 처리합니다. 매우 다른 것들.
jcsahnwaldt Reinstate Monica

1
내 경우에는 정확히 내가 필요한 것 :) (
OpenView

3
경고 : 아이폰에 6+이 당신이 원하는하지 않을 수있는 X 1920 1080를 반환
Chanon

8

iOS 8 SDK의 버그는 아닙니다. 그들은 경계 인터페이스 방향에 의존했습니다. 그 사실에 대한 일부 참조 또는 문서에 대한 귀하의 질문에 따르면 WWDC 2014의View Controller Advancements in iOS 8 214 세션 을 시청 하는 것이 좋습니다 . 가장 흥미로운 부분은 (의심에 따라) 50:45에서 시작하는 것입니다.Screen Coordinates


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 버전도 확인하는 것이 좋습니다.
Craig McMahon

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

불쾌하지만 시간이 제대로 물건을 고칠 수있을 때까지 일을 끝내십시오 :-)
DuneCat

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

그것이 올바른 rect를 계산하는 데 사용한 것입니다.

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 기능의 신속한 버전을 추가하는 것입니다.

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

// 장치를 더 추가 할 수도 있습니다 (iiPad).


화면 해상도에 따른 장치 인식에 관한 질문은 아닙니다. 또한 Apple은 장치 / 화면 감지가 아닌 크기 클래스를 기반으로하는 적응 형 UI를 만들 것을 권장합니다.
Julian Król

0

메인 화면 경계에서 min / max를 사용하여 iOS 버전 확인이없는 약간 수정 된 mnemia의 솔루션을 사용했습니다.
나는이 필요 CGRect하므로 가지고 CGRectmainscreen 범위에서 변경할 size.width=min(w,h), size.height=max(w,h). 그런 다음 CGRect코드의 두 위치에서 OS 독립적 get 함수를 호출했습니다.OpenGL , 터치 등 . 수정하기 전에 가로 모드의 IOS 8.x에서 2 가지 문제가 발생했습니다. OpenGL보기 위치 가 잘못되었습니다 : 1 / 왼쪽 하단 부분의 전체 화면 4 개. 그리고 두 번째 터치는 유효하지 않은 값을 반환했습니다. 두 문제 모두 설명 된대로 수정되었습니다. 감사!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.