[UIScreen mainScreen].bounds.size становится зависимым от ориентации в iOS8?

Я запускал следующий код как в 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

Есть ли какая-либо документация, определяющая это изменение? Или это временная ошибка в API iOS 8?

Ответ 1

Да, он ориентирован на ориентацию в iOS8, а не на ошибку. Вы можете просмотреть сеанс 214 из WWDC 2014 для получения дополнительной информации: "Просмотр улучшений контроллера в iOS 8"

Цитата из презентации:

UIScreen теперь ориентирован на интерфейс:

  • [UIScreen bounds] теперь ориентирован на интерфейс
  • [UIScreen applicationFrame] теперь ориентирован на интерфейс
  • Уведомления о состоянии строки состояния ориентированы на интерфейс
  • Уведомления о кадрах клавиатуры ориентированы на интерфейс.

Ответ 2

Да, он зависит от ориентации в iOS8.

Я написал метод 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;
}

Ответ 3

Да, действительно, размер экрана теперь зависит от ориентации в 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;
}

Ответ 4

Да, теперь он зависит от ориентации.

Я предпочитаю метод ниже, чтобы получить размер экрана не зависящим от ориентации способом к некоторым из вышеперечисленных ответов, так как он проще и потому что он не зависит от какого-либо кода ориентации (состояние которого может быть в зависимости от времени их вызова) или при проверке версий. Вам может потребоваться новое поведение iOS 8, но это будет работать, если вам нужно, чтобы он был стабильным во всех версиях iOS.

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

Ответ 5

В связи с этим вопросом, поскольку он решил мою проблему, здесь два определения используются для расчетов ширины и высоты экрана:

#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, это лучшее решение для этой проблемы.

Ответ 6

Это не ошибка в SDK iOS 8. Они сделали привязку ориентации границ.. По вашему вопросу о какой-либо ссылке или документации к этому факту я настоятельно рекомендую вам смотреть View Controller Advancements in iOS 8, это 214 сеанс из WWDC 2014. Самая интересная часть (по вашим сомнениям) - это Screen Coordinates, которая начинается в 50:45.

Ответ 7

Вы можете использовать nativeBounds (независимый от ориентации)

nativeBounds

Ограничивающий прямоугольник физического экрана, измеренный в пикселях. (Только для чтения)

Декларация SWIFT

  var nativeBounds: CGRect { get }

Этот прямоугольник основан на устройстве в портретной ориентации. Эта  Значение не изменяется при вращении устройства.

Обнаружение высоты устройства:

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

}

Обнаружение ширины устройства:

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

}

Ответ 8

Да, он зависит от ориентации в iOS8.

Здесь вы можете иметь согласованный способ чтения границ в моделях iOS 8 в SDK и OS-версиях.

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

Ответ 9

Мое решение - это комбинация 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;
}

Ответ 10

Мне нужна была быстрая вспомогательная функция, которая поддерживала то же поведение, что и iOS7 под iOS8 - это позволило мне поменять мои вызовы [[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;
}

Ответ 11

Этот метод можно использовать для определения границ экрана для заданной ориентации, независимо от версии iOS. Этот метод вернет границы на основе размера экрана устройства и предоставит то же значение CGRect, которое не зависит от версии iOS.

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

Ответ 13

То, что я использовал для вычисления правильного прямоугольника:

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

Ответ 14

Просто добавив быструю версию превосходной функции 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
}

Ответ 15

Одна вещь, которую я заметил, - это порядок поддерживаемых ориентаций интерфейса в Info.plist. У меня проблема с этим вопросом с моим приложением (то есть ориентация в коде), но я не указывал нигде, что ориентация по умолчанию - портрет.

Я думал, что ориентация по умолчанию была Portrait в любом случае.

Переупорядочивая itens в Info.plist, сначала поставив портрет, восстановив ожидаемое поведение.

Ответ 16

Используется слегка измененное решение для мнемий, без проверки версии iOS, с использованием min/max на границах главного экрана.
 Мне понадобился CGRect, поэтому получил CGRect с границ главного экрана и изменил size.width=min(w,h), size.height=max(w,h). Затем я назвал эту независимую от ОС функцию get CGRect в двух местах в моем коде, где я получаю размер экрана для OpenGL, касается и т.д. До исправления у меня было 2 проблемы - на IOS 8.x в режиме ландшафтного режима отображалось положение Неверное изображение OpenGL: 1/4 полного экрана в левой нижней части. И второе касание возвращает недопустимые значения. Обе проблемы были исправлены, как объяснено. Спасибо!

Ответ 17

Моя проблема была связана с кадром UIWindows, который шел минус. Так сделал код, как показано ниже в MyViewController - (NSUInteger) supportedInterfaceOrientations Method

[[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)];

И его работа для меня попробовать.

Ответ 18

Это даст правильное устройство в 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;
}

//Вы можете добавить еще несколько устройств (например, iPad).

Ответ 19

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