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

이것은 iOS7 과 iOS8 에서 올바른 장치를 제공합니다 .

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