Comment obtenir la hauteur et la largeur de l'écran en fonction de l'orientation?

96

J'essaie de déterminer par programme la hauteur et la largeur actuelles de mon application. J'utilise ceci:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Mais cela donne une largeur de 320 et une hauteur de 480, que l'appareil soit en orientation portrait ou paysage. Comment puis - je déterminer le courant largeur et la hauteur (c. -à- dépendant de l'orientation de l' appareil) de mon écran principal?

MusiGenesis
la source

Réponses:

164

Vous pouvez utiliser quelque chose comme UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)pour déterminer l'orientation, puis utiliser les dimensions en conséquence.

TOUTEFOIS, lors d'un changement d'orientation comme dans UIViewController

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 
                                 duration:(NSTimeInterval)duration

Utiliser l'orientation transmise toInterfaceOrientation car statusBarOrientation de l'UIApplication pointera toujours vers l'ancienne orientation car elle n'a pas encore changé (puisque vous êtes dans un willgestionnaire d'événements).

Résumé

Il y a plusieurs articles liés à cela, mais chacun d'eux semble indiquer que vous devez:

  1. Regarder [[UIScreen mainScreen] bounds] pour obtenir les dimensions,
  2. Vérifiez dans quelle orientation vous vous trouvez et
  3. Tenez compte de la hauteur de la barre d'état (si affichée)

Liens

Code de travail

Je ne vais généralement pas aussi loin, mais vous avez piqué mon intérêt. Le code suivant devrait faire l'affaire. J'ai écrit une catégorie sur UIApplication. J'ai ajouté des méthodes de classe pour obtenir le currentSize ou la taille dans une orientation donnée, ce que vous appelleriez dans UIViewController willRotateToInterfaceOrientation:duration:.

@interface UIApplication (AppDimensions)
+(CGSize) currentSize;
+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation;
@end

@implementation UIApplication (AppDimensions)

+(CGSize) currentSize
{
    return [UIApplication sizeInOrientation:[UIApplication sharedApplication].statusBarOrientation];
}

+(CGSize) sizeInOrientation:(UIInterfaceOrientation)orientation
{
    CGSize size = [UIScreen mainScreen].bounds.size;
    UIApplication *application = [UIApplication sharedApplication];
    if (UIInterfaceOrientationIsLandscape(orientation))
    {
        size = CGSizeMake(size.height, size.width);
    }
    if (application.statusBarHidden == NO)
    {
        size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height);
    }
    return size;
}

@end

Pour utiliser le code appel simple [UIApplication currentSize]. En outre, j'ai exécuté le code ci-dessus, donc je sais que cela fonctionne et renvoie les bonnes réponses dans toutes les orientations. Notez que je prends en compte la barre d'état. Fait intéressant, j'ai dû soustraire le MIN de la hauteur et de la largeur de la barre d'état.

J'espère que cela t'aides. :RÉ

D'autres pensées

Vous pouvez obtenir les dimensions en regardant la rootViewControllerpropriété UIWindow . J'ai regardé cela dans le passé et il rapporte de la même manière les mêmes dimensions en portrait et en paysage, sauf qu'il rapporte avoir une transformation de rotation:

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] vue]

<UILayoutContainerView: 0xf7296f0; cadre = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = W + H; layer = <CALayer: 0xf729b80 >>

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] vue]

<UILayoutContainerView: 0xf7296f0; cadre = (0 0; 320 480); autoresize = W + H; layer = <CALayer: 0xf729b80 >>

Vous ne savez pas comment votre application fonctionne, mais si vous n'utilisez pas de contrôleur de navigation, vous pourriez avoir un UIView sous votre vue principale avec la hauteur / largeur maximale du parent et grandir / rétrécir avec le parent. Ensuite, vous pouvez faire:[[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame] . Cela semble assez intense sur une seule ligne, mais vous voyez l'idée.

Cependant ... Il serait toujours préférable de faire les 3 étapes ci-dessus sous le résumé. Commencez à jouer avec UIWindows et vous découvrirez des trucs étranges, comme montrer un UIAlertView changera la fenêtre de clé d'UIApplication pour pointer vers une nouvelle UIWindow créée par UIAlertView. Qui savait? Je l'ai fait après avoir trouvé un bogue en s'appuyant sur keyWindow et découvert qu'il avait changé comme ça!

Sam
la source
5
Cela semble être une tâche tellement élémentaire que j'ai du mal à croire que je dois pirater mon propre code pour déterminer quelque chose comme ça.
MusiGenesis
2
Je vais essayer une autre solution et republier si cela fonctionne. Ce site est tellement agressif si vous ne répondez pas rapidement, vous pourriez aussi bien ne pas répondre du tout. haha ...: J'espère que ma réponse est au moins utile. Encore une fois, je vais essayer autre chose très rapidement.
Sam
1
Génial! (BTW, on a son intérêt piqué) :-)
Vamos
1
Si vous utilisez à la applicationFrameplace de bounds(sur UIScreen), vous n'avez pas à soustraire la hauteur de la barre d'état.
aopsfan
2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size est devenu dépendant de l'orientation à partir d'iOS 8
Gerald
39

Ceci est mon code de solution! Cette méthode peut s'ajouter au Categroy de la classe NSObject, ou vous pouvez définir une classe UIViewController personnalisée Top et laisser tous vos autres UIViewControllers l'hériter.

-(CGRect)currentScreenBoundsDependOnOrientation
{  

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
    }
    return screenBounds ;
}

Notez , après IOS8, comme le dit le document Apple de la propriété bounds d'UIScreen :

Discussion

Ce rectangle est spécifié dans l'espace de coordonnées courant, qui prend en compte les éventuelles rotations d'interface en vigueur pour l'appareil. Par conséquent, la valeur de cette propriété peut changer lorsque l'appareil pivote entre les orientations portrait et paysage.

Donc, pour tenir compte de la compatibilité, nous devons détecter la version IOS et effectuer le changement comme ci-dessous:

#define IsIOS8 (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1)

-(CGRect)currentScreenBoundsDependOnOrientation
{  

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    if(IsIOS8){
        return screenBounds ;
    }
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
    }
    return screenBounds ;
}
monjer
la source
À peu près la même chose que ma réponse, la seule chose qui lui manque, c'est si elle est en Portrait à l'envers. Cela n'a d'importance que si vous soutenez cette orientation tho.
Robert Wagstaff
2
@Monjer vous ne devez pas nommer les méthodes qui n'effectuent pas de requête GET, avec le préfixe i du mot get. currentScreenBoundsDependOnOrientation est un meilleur nom pour la méthode
bogen
1
@ Hakonbogen.yes peut-être que vous avez raison, car la déclaration «peroperty» génère automatiquement la méthode setter / getter, ce qui peut conduire à un conflit de dénomination et aller à l'encontre des conventions de dénomination d'objc. Merci pour vos conseils.
monjer
C'est bien qu'Apple ait finalement reconnu tacitement que leur code de rotation était un gâchis complet, et a juste commencé à nous dire quelles sont les foutues dimensions dans l'orientation actuelle. Dommage qu'il ait fallu attendre la version 8 pour y arriver.
MusiGenesis
30

Voici une macro pratique:

#define SCREEN_WIDTH (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.width : [[UIScreen mainScreen] bounds].size.height)
#define SCREEN_HEIGHT (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation) ? [[UIScreen mainScreen] bounds].size.height : [[UIScreen mainScreen] bounds].size.width)
Robert Wagstaff
la source
14

Dans iOS 8+, vous devez utiliser la viewWillTransitionToSize:withTransitionCoordinatorméthode:

-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // You can store size in an instance variable for later
    currentSize = size;

    // This is basically an animation block
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Get the new orientation if you want
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

        // Adjust your views
        [self.myView setFrame:CGRectMake(0, 0, size.width, size.height)];

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        // Anything else you need to do at the end
    }];
}

Cela remplace la méthode d'animation obsolète qui ne donnait aucune information sur la taille:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
Mark Hennings
la source
Cela devrait être la réponse acceptée. Moderne et à jour.
SarpErdag
Utilisez cette réponse pour iOS 8 et supérieur.
iPhoneDeveloper
10

À partir d'iOS 8, les limites de l'écran sont désormais renvoyées correctement pour l'orientation actuelle. Cela signifie qu'un iPad en orientation paysage [UIScreen mainScreen] .bounds renverrait 768 sur iOS <= 7 et 1024 sur iOS 8.

Ce qui suit renvoie la hauteur et la largeur correctes sur toutes les versions publiées.

-(CGRect)currentScreenBoundsDependOnOrientation
{
    NSString *reqSysVer = @"8.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
        return [UIScreen mainScreen].bounds;

    CGRect screenBounds = [UIScreen mainScreen].bounds ;
    CGFloat width = CGRectGetWidth(screenBounds)  ;
    CGFloat height = CGRectGetHeight(screenBounds) ;
    UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;

    if(UIInterfaceOrientationIsPortrait(interfaceOrientation)){
        screenBounds.size = CGSizeMake(width, height);
        NSLog(@"Portrait Height: %f", screenBounds.size.height);
    }else if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
        screenBounds.size = CGSizeMake(height, width);
        NSLog(@"Landscape Height: %f", screenBounds.size.height);
    }

    return screenBounds ;
}
A. Badger
la source
8

si vous voulez la taille dépendante de l'orientation et que vous avez une vue, vous pouvez simplement utiliser:

view.bounds.size
Tod
la source
GÉNIAL! KISS solution = Keep It Simple and Stupid
bsorrentino
3
KISS ne veut pas dire "Keep it Simple and Stupid" - LOL! Cela signifie "Restez simple, stupide!" :-)
Erik van der Neut
De plus, cette réponse ne fonctionne évidemment que si votre vue est connue pour être exactement en plein écran. Mais, si tel était le cas, alors vous n'avez probablement pas le problème d'origine signalé par l'OP.
Erik van der Neut
5

Je l' ai écrit pour la catégorie UIScreen, qui fonctionne sur toutes les versions iOS, vous pouvez donc l' utiliser comme ceci:
[[UIScreen mainScreen] currentScreenSize].

@implementation UIScreen (ScreenSize)

- (CGSize)currentScreenSize {
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    CGSize screenSize = screenBounds.size;

    if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {  
        UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if ( UIInterfaceOrientationIsLandscape(interfaceOrientation) ) {
            screenSize = CGSizeMake(screenSize.height, screenSize.width);
        }
    }

    return screenSize;
}

@end
ArtFeel
la source
1
Cela me semble être la réponse la plus claire. Voté.
Erik van der Neut
5

Voici un moyen Swift d'obtenir des tailles d'écran dépendant de l'orientation:

var screenWidth: CGFloat {
    if UIInterfaceOrientationIsPortrait(screenOrientation) {
        return UIScreen.mainScreen().bounds.size.width
    } else {
        return UIScreen.mainScreen().bounds.size.height
    }
}
var screenHeight: CGFloat {
    if UIInterfaceOrientationIsPortrait(screenOrientation) {
        return UIScreen.mainScreen().bounds.size.height
    } else {
        return UIScreen.mainScreen().bounds.size.width
    }
}
var screenOrientation: UIInterfaceOrientation {
    return UIApplication.sharedApplication().statusBarOrientation
}

Ceux-ci sont inclus en tant que fonction standard dans un de mes projets:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
la source
0
float msWidth = [[UIScreen mainScreen] bounds].size.width*(IS_RETINA?2.0f:1.0f);
float msHeight = [[UIScreen mainScreen] bounds].size.height*(IS_RETINA?2.0f:1.0f);
if ( UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ) {
    os->setWidth(MIN(msWidth, msHeight));
    os->setHeight(MAX(msWidth, msHeight));
} else {
    os->setWidth(MAX(msWidth, msHeight));
    os->setHeight(MIN(msWidth, msHeight));
}

NSLog(@"screen_w %f", os->getWidth());
NSLog(@"screen_h %f", os->getHeight());
user4082558
la source
0

Cependant, sur iOS 8.0.2:

+ (NSUInteger)currentWindowWidth
{
    NSInteger width = 0;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    CGSize size = [UIScreen mainScreen].bounds.size;
   // if (UIInterfaceOrientationIsLandscape(orientation)) {
   //     width = size.height;
   // } else {
        width = size.width;
  //  }

    return width;
}
Gank
la source
0

utilisez -> setNeedsDisplay () pour la vue que vous souhaitez redimensionner.

Santosh
la source