¿Es [UIScreen mainScreen] .bounds.size dependiente de la orientación en iOS8?


184

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

En comparación con el resultado en iOS 7:

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

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


13
Bueno, la salida de iOS8 parece mucho más lógica
Levi

Respuestas:


173

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

Cita de la presentación:

UIScreen ahora está orientado a la interfaz:

  • [Límites UIScreen] 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

77
En la conferencia WWDC mencionada anteriormente, la parte orientada a la interfaz comienza a las 51:50.
cnotethegr8

2
He pasado la mayor parte del día tratando de evitar este avance. Aparentemente no siempre sucede, así que si eres un desarrollador de un SDK que necesita trabajar en otras aplicaciones, esto se vuelve aún más complicado.
Glenn Maynard

1
@ Aroth no puedes innovar sin frenar algunos viejos hábitos.
Boris Y.

23
@borisy - Estoy respetuosamente en desacuerdo. En la mayoría de los casos, es posible innovar mientras se preserva la compatibilidad con versiones anteriores. Romper cambios huele a pereza más que cualquier otra cosa, en mi opinión. Quieren que todos los demás hagan el trabajo.
Aroth

1
Esta respuesta sería aún más útil si se explicara qué significa realmente orientado a la interfaz . Puedo estar equivocado, pero creo que la dependencia de la orientación solo pertenece a los controladores de vista. Si toma cualquier otra clase y calcula los límites, todavía están de acuerdo con el estilo anterior, siempre vertical.
Maxi Mus

59

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

Escribí un método Util para resolver este problema para aplicaciones que necesitan admitir 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;
}

1
Edité el código, por favor verifique, su condición para verificar la versión del sistema operativo era incorrecta
Jageen

@Jageen Por favor aclare, la verificación de la versión funciona para mí. ¿Cuál es el problema?
cbartel

Lo que entiendo es que necesitamos cambiar la altura y el ancho si el sistema operativo es iOS8 y la orientación es horizontal, ¿estoy en lo cierto?
Jageen

@Jageen Negative, en iOS 8 el método depende de la orientación. Tu lógica ha cambiado. Su edición fue rechazada correctamente.
cbartel

@cbartel, ¿hay alguna manera de clasificar esto en UIScreen para que nuestra llamada original a [UIScreen mainScreen] .bounds.size funcione tanto para iOS 7 como para iOS 8?
kevinl

34

Sí, de hecho, el tamaño de la pantalla ahora depende de la orientación en iOS 8. A veces, sin embargo, se desea obtener un tamaño fijo a la 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;
}

2
Estoy descubriendo que esto soluciona el problema con las aplicaciones normales de iPhone, pero no con las aplicaciones de iPhone que se ejecutan en iPad.
ThomasW

32

Sí, ahora depende de la orientación.

Prefiero el siguiente método para obtener el tamaño de la pantalla de forma independiente de la orientación a algunas de las respuestas anteriores, tanto porque es más simple como porque no depende de ninguno de los códigos de orientación (cuyo estado puede depender de hora en que se llaman) o en la comprobación de 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));
}

Sin embargo, probablemente no funcionará en algo como Apple TV, donde es (casi) siempre más ancho que alto.
cbh2000

11

En relación con esta pregunta, ya que resolvió mi problema, aquí hay dos definiciones que uso para los cálculos de ancho y alto de pantalla:

#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 es compatible con iOS 7 y iOS 8, esta es la mejor solución para este problema.


@Namit Gupta, tu edición es incorrecta. Si la versión de IOS es 8 o superior, podemos usar las dimensiones de la pantalla UIS ya que estas dependen de la orientación. Antes de iOS 8 tenía que verificar la orientación de la barra de estado. Su edición ahora dice que todas las versiones de iOS que no sean inferiores a 8 deberían verificar la orientación de la barra de estado, lo cual es incorrecto.
Antoine

9

Puede usar nativeBounds(orientación independiente)

nativeBounds

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 {

}

3
Tenga en cuenta que este método devuelve píxeles, mientras que la mayoría de los otros métodos tratan con puntos. Cosas muy diferentes.
jcsahnwaldt Restablece a Mónica el

1
En mi caso, exactamente lo que necesitaba :) (OpenGL u otras vistas no basadas en UIViews pero donde necesito saber las dimensiones exactas de los píxeles)
Bersaelor

3
Advertencia: en el iPhone 6+, esto devolvió 1080 x 1920, que podría no ser lo que quieres
Chanon

8

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


5

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

Así es como puede tener una forma coherente de leer los límites de una manera 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

1
Verificar la versión del SDK también es un buen consejo en caso de que sus colegas estén creando su aplicación con diferentes versiones del SDK (¡aunque eso no debería estar sucediendo!).
Craig McMahon

4

Mi solución es una combinación de MaxK's 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 - 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

Necesitaba una función de ayuda rápida que mantuviera el mismo comportamiento que iOS7 en iOS8; esto me permitió intercambiar mis [[UIScreen mainScreen] bounds]llamadas 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;
}

Desagradable, pero hace el trabajo hasta que se pueda dedicar tiempo a arreglar las cosas correctamente :-)
DuneCat

3

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

1

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

1

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

1

Mi problema estaba relacionado con el marco UIWindows que iba en menos. Así que hice el código de la siguiente manera en MyViewController - (NSUInteger) supportInterfaceOrientations 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 es trabajo para mí intentarlo.


1

iOS 8 o superior

Una solución para aquellos que desean averiguar 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;
    }
}

0

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 tiene orientación en el código), pero no especifiqué en ningún lugar que la orientación predeterminada sea Vertical.

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

La reorganización de itens en Info.plist, poniendo primero a Portrait, restauró el comportamiento esperado.


0

Esto le dará al dispositivo correcto en iOS7 y 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 puede agregar más dispositivos (ieiPad).


La pregunta no es sobre el reconocimiento del dispositivo basado en la resolución de la pantalla. Además, Apple recomienda crear una interfaz de usuario adaptativa que se base en clases de tamaño, no en detección de dispositivo / pantalla
Julian Król

0

Se utilizó la solución de mnemia ligeramente modificada, aquella sin verificación de versión de iOS, usando min / max en los límites de la pantalla principal.
Necesitaba un CGRectmodo tiene CGRectde límites Principal Pantalla Principal y cambiaron size.width=min(w,h), size.height=max(w,h). Entonces llamé a que se interponen independiente del sistema operativo CGRectfunción en dos lugares en mi código, donde conseguir tamaño de pantalla para OpenGL, toques etc., antes de fijar tuve 2 problemas - en IOS 8.x en el paisaje de la posición de visualización del modo de OpenGLvista era incorrecta: 1 / 4 de pantalla completa en la parte inferior izquierda. Y los segundos toques devolvieron valores no válidos. Ambos problemas se solucionaron como se explicó. ¡Gracias!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.