Est-ce que [UIScreen mainScreen] .bounds.size devient dépendant de l'orientation dans iOS8?

184

J'ai exécuté le code suivant dans iOS 7 et 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);

Voici le résultat d'iOS 8:

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

Comparé au résultat dans iOS 7:

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

Existe-t-il une documentation spécifiant ce changement? Ou est-ce un bogue temporaire dans les API iOS 8?

lwxted
la source
13
Eh bien, la sortie iOS8 semble beaucoup plus logique
Levi

Réponses:

173

Oui, cela dépend de l'orientation dans iOS8, pas un bogue. Vous pouvez consulter la session 214 de la WWDC 2014 pour plus d'informations: «Afficher les avancées du contrôleur dans iOS 8»

Citation de la présentation:

UIScreen est désormais orienté interface:

  • [UIScreen bounds] désormais orienté interface
  • [UIScreen applicationFrame] désormais orienté interface
  • Les notifications par cadre de la barre d'état sont orientées vers l'interface
  • Les notifications de cadre de clavier sont orientées vers l'interface
vhristoskov
la source
7
Dans la conférence WWDC mentionnée ci-dessus, la partie orientée interface commence à 51:50.
cnotethegr8
2
J'ai passé la majeure partie de la journée à essayer de contourner cette avancée. Apparemment, cela ne se produit pas toujours , donc si vous êtes un développeur d'un SDK qui doit fonctionner dans d'autres applications, cela devient encore plus compliqué.
Glenn Maynard
1
@aroth vous ne pouvez pas innover sans freiner certaines vieilles habitudes.
Boris Y.29
23
@borisy - Je suis respectueusement en désaccord. Dans la plupart des cas, il est possible d'innover tout en préservant la rétrocompatibilité. À mon avis, les changements de rupture sentent la paresse plus que toute autre chose. Ils veulent que tout le monde fasse le travail.
aroth
1
Cette réponse serait encore plus utile s'il était expliqué ce que signifie réellement l' interface . Je me trompe peut-être, mais je pense que la dépendance d'orientation ne concerne que les contrôleurs de vue. Si vous prenez une autre classe et calculez les limites, elles sont toujours selon l'ancien style, toujours portrait.
Maxi Mus
59

Oui, cela dépend de l'orientation dans iOS8.

J'ai écrit une méthode Util pour résoudre ce problème pour les applications qui doivent prendre en charge les anciennes versions du système d'exploitation.

+ (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;
}
cbartel
la source
1
J'ai modifié le code s'il vous plaît vérifier, votre condition pour vérifier la version du système d'exploitation était incorrecte
Jageen
@Jageen Veuillez clarifier, la vérification de version fonctionne pour moi. Quel est le problème?
cbartel le
Ce que je comprends, c'est que nous devons changer la hauteur et la largeur si le système d'exploitation est iOS8 et l'orientation est Paysage, ai-je raison?
Jageen
@Jageen Negative, dans iOS 8, la méthode dépend de l'orientation. Votre logique est inversée. Votre modification a été correctement rejetée.
cbartel
@cbartel existe-t-il un moyen de catégoriser cela dans UIScreen afin que notre appel initial à [UIScreen mainScreen] .bounds.size fonctionne à la fois pour iOS 7 et iOS 8?
kevinl le
34

Oui, en effet, la taille de l'écran dépend désormais de l'orientation dans iOS 8. Parfois, cependant, il est souhaitable d'obtenir une taille fixée à l'orientation portrait. Voici comment je le fais.

+ (CGRect)screenBoundsFixedToPortraitOrientation {
    UIScreen *screen = [UIScreen mainScreen];

    if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) {
                    return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace];
    } 
    return screen.bounds;
}
MaxK
la source
2
Je trouve que cela résout le problème avec les applications iPhone classiques, mais pas avec les applications iPhone fonctionnant sur iPad.
ThomasW
32

Oui, cela dépend désormais de l'orientation.

Je préfère la méthode ci-dessous pour obtenir la taille de l'écran d'une manière indépendante de l'orientation à certaines des réponses ci-dessus, à la fois parce qu'elle est plus simple et parce qu'elle ne dépend d'aucun code d'orientation (dont l'état peut dépendre du heure de leur appel) ou lors de la vérification de version. Vous voudrez peut-être le nouveau comportement d'iOS 8, mais cela fonctionnera si vous en avez besoin pour être stable sur toutes les versions d'iOS.

+(CGSize)screenSizeOrientationIndependent {
     CGSize screenSize = [UIScreen mainScreen].bounds.size;
     return CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
}
mnémie
la source
Cependant, cela ne fonctionnera probablement pas sur quelque chose comme Apple TV, où il est (presque) toujours plus large que haut.
cbh2000
11

Lié à cette question car elle a résolu mon problème, voici deux définitions que j'utilise pour les calculs de largeur et de hauteur d'écran:

#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 vous prenez en charge à la fois iOS 7 et iOS 8, c'est la meilleure solution à ce problème.

Antoine
la source
@Namit Gupta, votre modification est erronée. Si la version IOS est 8 ou supérieure, nous pouvons utiliser les dimensions UIScreen car elles dépendent de l'orientation. Avant iOS 8, vous deviez vérifier l'orientation de la barre d'état. Votre modification indique maintenant que toutes les versions d'iOS non inférieures à 8 devraient vérifier l'orientation de la barre d'état, ce qui est faux.
Antoine
9

Vous pouvez utiliser nativeBounds(indépendamment de l'orientation)

nativeBounds

Le rectangle englobant de l'écran physique, mesuré en pixels. (lecture seulement)

Déclaration SWIFT

  var nativeBounds: CGRect { get }

Ce rectangle est basé sur l'appareil dans une orientation portrait vers le haut. Cette valeur ne change pas lorsque l'appareil tourne.

Détection de la hauteur de l'appareil:

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

}

Détection de la largeur de l'appareil:

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

}
Leo Dabus
la source
3
Sachez que cette méthode renvoie des pixels, alors que la plupart des autres méthodes traitent des points. Des choses très différentes.
jcsahnwaldt Réintègre Monica le
1
Dans mon cas, exactement ce dont j'avais besoin :) (OpenGL ou autres vues non basées sur UIViews mais où j'ai besoin de connaître les dimensions exactes des pixels)
Bersaelor
3
Attention: sur iphone 6+, cela a renvoyé 1080 x 1920, ce qui n'est peut-être pas ce que vous voulez
Chanon
8

Ce n'est pas un bogue dans le SDK iOS 8. Ils ont fait dépendre l'orientation de l'interface des limites. Selon votre question sur une référence ou une documentation sur ce fait, je vous recommanderai fortement de regarder la View Controller Advancements in iOS 8session 214 de la WWDC 2014 . La partie la plus intéressante (selon vos doutes) est celle Screen Coordinatesqui commence à 50h45.

Julian Król
la source
5

Oui, cela dépend de l'orientation dans iOS8.

Voici comment vous pouvez avoir un moyen cohérent de lire les limites à la manière d'iOS 8 sur les versions du SDK et du système d'exploitation.

#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
hfossli
la source
1
La vérification de la version du SDK est également un bon conseil au cas où des collègues construiraient votre application avec différentes versions du SDK (bien que cela ne devrait pas se produire!).
Craig McMahon
4

Ma solution est une combinaison de MaxK et hfossli. J'ai fait cette méthode sur une catégorie d'UIScreen et il n'y a pas de vérification de version (ce qui est une mauvaise pratique):

//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;
}
Uzair Khan
la source
3

J'avais besoin d'une fonction d'aide rapide qui gardait le même comportement qu'iOS7 sous iOS8 - cela m'a permis d'échanger mes [[UIScreen mainScreen] bounds]appels et de ne pas toucher d'autre code ...

+ (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;
}
Joe Booth
la source
Nasty, mais fait le travail jusqu'à ce que le temps puisse être mis à réparer les choses correctement :-)
DuneCat
3

La méthode ci-dessous peut être utilisée pour trouver les limites de l'écran pour une orientation donnée, indépendamment de la version iOS. Cette méthode renverra les limites en fonction de la taille de l'écran de l'appareil et donnera la même valeur CGRect indépendamment de la version 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]; 

la source
1

C'est ce que j'ai utilisé pour calculer le bon 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
hhamm
la source
1

L'ajout de la version rapide d'une excellente fonction cbartel a répondu ci-dessus.

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
}
Martin Koles
la source
1

Mon problème était lié au cadre UIWindows qui allait en moins. Donc, faites le code comme ci-dessous dans MyViewController - (NSUInteger) supportedInterfaceOrientations, méthode

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

Et son travail pour moi l'essayer.

Hardik Mamtora
la source
1

iOS 8 ou supérieur

Une solution pour ceux qui veulent connaître la taille de l'écran en points (l'écran de 3,5 pouces a 320 × 480 points, l'écran de 4,0 pouces a 320 × 568 points, etc.) serait

- (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;
    }
}
Stefan
la source
0

Une chose que j'ai notée est que l' ordre des orientations d'interface prises en charge dans Info.plist importe. J'ai eu le problème de cette question avec mon application (qui fait l'orientation dans le code), mais je n'ai spécifié nulle part que l'orientation par défaut est Portrait.

Je pensais que l'orientation par défaut était Portrait en tout cas.

La réorganisation des itens dans Info.plist, en mettant Portrait en premier, a restauré le comportement attendu.

epx
la source
0

Cela donnera le bon appareil dans iOS7 et iOS8 à la fois,

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

// Vous pouvez également ajouter d'autres appareils (ieiPad).

Mohammad Zaid Pathan
la source
La question ne concerne pas la reconnaissance de l'appareil en fonction de la résolution de l'écran. De plus, Apple recommande de créer une interface utilisateur adaptative basée sur des classes de taille et non sur la détection d'appareil / écran
Julian Król
0

Utilisé la solution de mnemia légèrement modifiée, celle-là sans vérification de version iOS, utilisant min / max sur les limites de l'écran principal.
Il me fallait un CGRectsi obtenu CGRectde limites mainScreen et changé size.width=min(w,h), size.height=max(w,h). Ensuite , j'ai appelé ce système d' exploitation indépendant get CGRectfonction en deux endroits dans mon code, où j'obtenir la taille de l' écran pour OpenGL, des touches , etc. Avant de fixer j'ai eu 2 problèmes - sur IOS 8.x en position d'affichage en mode paysage de OpenGLvue était incorrecte: 1 / 4 de plein écran dans la partie inférieure gauche. Et les secondes touches ont renvoyé des valeurs invalides. Les deux problèmes ont été résolus comme expliqué. Merci!

Pas d'ange
la source