Есть [uiscreen mainScreen].границы.размер становится зависимым от ориентации в 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?

18 178

18 ответов:

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

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

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

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

Да, это зависит от ориентации в 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;
}

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

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

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

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

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

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

можно использовать nativeBounds (ориентация-независимая)

nativeBounds

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

объявление SWIFT

  var nativeBounds: CGRect { get }

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

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

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

}

определение ширины устройства:

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

}

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

Да, это зависит от ориентации в 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'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

мое решение представляет собой комбинацию 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;
}

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

ниже метод может быть использован для поиска границ экрана для данной ориентации, независимо от версии 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]; 

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

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

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

моя проблема была связана с фреймом 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)];

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

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

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

перестановка itens в Info.плист, поставив портрет первым, восстановил ожидаемое поведение.

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

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

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