¿Está .bounds.size convirtiéndose en dependiente de la orientación en iOS8?

Ejecuté el siguiente código tanto en iOS 7 como en 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); 

El siguiente es el resultado de iOS 8:

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

Comparando con el resultado en iOS 7:

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

¿Hay alguna documentación que especifique este cambio? ¿O es un error temporal en las API de iOS 8?

Sí, depende de la orientación en iOS8, no es un error. Puede revisar la sesión 214 de la WWDC 2014 para obtener más información: “Ver avances del controlador en iOS 8”

Cita de la presentación:

UIScreen ahora está orientado a la interfaz:

  • [UIScreen bounds] ahora orientado a la interfaz
  • [UIScreen applicationFrame] ahora orientado a la interfaz
  • Las notificaciones del marco de la barra de estado están orientadas a la interfaz
  • Las notificaciones del marco del teclado están orientadas a la interfaz

Sí, depende de la orientación en iOS8.

Escribí un método Util para resolver este problema para las aplicaciones que necesitan compatibilidad con versiones anteriores del sistema operativo.

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

Sí, de hecho, el tamaño de la pantalla ahora depende de la orientación en iOS 8. Algunas veces, sin embargo, se desea obtener un tamaño fijo para orientación vertical. Así es como lo hago.

 + (CGRect)screenBoundsFixedToPortraitOrientation { UIScreen *screen = [UIScreen mainScreen]; if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) { return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace]; } return screen.bounds; } 

Sí, ahora depende de la orientación.

Prefiero el siguiente método para obtener el tamaño de la pantalla de una manera independiente de la orientación de algunas de las respuestas anteriores, tanto porque es más simple y porque no depende de ningún código de orientación (el estado del cual puede depender de la vez que se les llama) o en la verificación de la versión. Es posible que desee el nuevo comportamiento de iOS 8, pero esto funcionará si necesita que sea estable en todas las versiones de iOS.

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

En relación con esta pregunta, ya que resolvió mi problema, aquí dos define que uso para el ancho de la pantalla y los cálculos de altura:

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

Si está soportando iOS 7 e iOS 8, esta es la mejor solución para este problema.

Puedes usar nativeBounds (orientación-independiente)

Pueblos nativos

El rectángulo delimitador de la pantalla física, medido en píxeles. (solo lectura)

Declaración SWIFT

  var nativeBounds: CGRect { get } 

Este rectángulo se basa en el dispositivo en una orientación vertical. Este valor no cambia a medida que el dispositivo gira.

Detectando la altura del dispositivo:

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

Detectando el ancho del dispositivo:

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

No es un error en iOS 8 SDK. Hicieron que la interfaz dependiera de la orientación de los límites. De acuerdo con su pregunta sobre alguna referencia o documentación sobre ese hecho, le recomendaré encarecidamente que mire View Controller Advancements in iOS 8 , es 214 sesión de WWDC 2014 . La parte más interesante (de acuerdo con sus dudas) es Screen Coordinates que comienza a las 50:45.

Sí, depende de la orientación en iOS8.

A continuación, le mostramos cómo puede tener una forma concisa de leer los límites de iOS 8 en las versiones de SDK y 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 

Mi solución es una combinación de MaxK y hfossli. Hice este método en una categoría de UIScreen y no tiene verificaciones de versión (lo cual es una mala práctica):

 //Always return the iOS8 way - ie 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; } 

Necesitaba una función de ayuda rápida que mantuviera el mismo comportamiento que iOS7 en iOS8; esto me permitió cambiar mis [[UIScreen mainScreen] bounds] y no tocar otro código …

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

El siguiente método se puede utilizar para encontrar los límites de la pantalla para una orientación determinada, independientemente de la versión de iOS. Este método devolverá los límites según el tamaño de pantalla del dispositivo y dará el mismo valor de CGRect independientemente de la versión de 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]; 

Eso es lo que solía calcular el rect correcto:

 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 

Solo agregue la versión rápida de una excelente función cbartel respondida anteriormente.

 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 } 

Mi problema estaba relacionado con el marco de UIWindows que entraba en menos. Así que hice el código de la siguiente manera en 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)]; 

Y su trabajo para mí, pruébalo.

Una cosa que noté es que el orden de las orientaciones de interfaz compatibles en Info.plist sí importa. Tengo el problema de esta pregunta con mi aplicación (que hace la orientación en el código), pero no especifiqué que la orientación predeterminada sea Vertical.

Pensé que la orientación predeterminada era Portrait en cualquier caso.

Reorganizar itens en Info.plist, al poner Portrait primero, restaura el comportamiento esperado.

Esto dará el dispositivo correcto en iOS7 e iOS8 ambos,

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

// También puedes agregar más dispositivos (ieiPad).

iOS 8 o superior

Una solución para aquellos que quieren saber el tamaño de la pantalla en puntos (la pantalla de 3.5 pulgadas tiene 320 × 480 puntos, la pantalla de 4.0 pulgadas tiene 320 × 568 puntos, etc.) sería

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

Usé la solución de mnemia ligeramente modificada, la que no tiene la versión de iOS verificada, usando min / max en los límites de la pantalla principal.
Necesitaba un CGRect así que obtuve CGRect de los límites de la pantalla principal y cambié size.width=min(w,h) , size.height=max(w,h) . Luego llamé a esa función de obtención de CGRect independiente del CGRect operativo en dos lugares de mi código, donde obtuve el tamaño de pantalla para OpenGL , toques, etc. Antes de solucionar tuve 2 problemas: en iOS 8.x en modo horizontal la posición de visualización de OpenGL era incorrecta : 1/4 de pantalla completa en la parte inferior izquierda. Y los segundos toques devolvieron valores inválidos. Ambos problemas fueron arreglados como se explicó. ¡Gracias!