Wie erhalte ich eine orientierungsabhängige Höhe und Breite des Bildschirms?

96

Ich versuche, die aktuelle Höhe und Breite meiner Anwendung programmgesteuert zu bestimmen. Ich benutze das:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Dies ergibt jedoch eine Breite von 320 und eine Höhe von 480, unabhängig davon, ob sich das Gerät im Hoch- oder Querformat befindet. Wie kann ich die aktuelle Breite und Höhe (dh abhängig von der Geräteorientierung) meines Hauptbildschirms bestimmen ?

MusiGenesis
quelle

Antworten:

164

Sie können so etwas wie UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)die Ausrichtung bestimmen und dann die Abmessungen entsprechend verwenden.

JEDOCH während einer Orientierungsänderung wie bei UIViewController

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

Verwenden Sie die übergebene Ausrichtung, toInterfaceOrientationda die statusBarOrientation der UIApplication weiterhin auf die alte Ausrichtung verweist, da sie sich noch nicht geändert hat (da Sie sich in einem willEreignishandler befinden).

Zusammenfassung

Es gibt mehrere verwandte Beiträge dazu, aber jeder von ihnen scheint darauf hinzudeuten, dass Sie:

  1. Schauen Sie [[UIScreen mainScreen] bounds]sich die Maße an,
  2. Überprüfen Sie, in welcher Ausrichtung Sie sich befinden, und
  3. Berücksichtigen Sie die Höhe der Statusleiste (falls angezeigt).

Links

Arbeitscode

Normalerweise gehe ich nicht so weit, aber Sie haben mein Interesse geweckt. Der folgende Code sollte den Trick machen. Ich habe eine Kategorie über UIApplication geschrieben. Ich habe Klassenmethoden hinzugefügt, um die aktuelle Größe oder die Größe in einer bestimmten Ausrichtung zu erhalten willRotateToInterfaceOrientation:duration:. Dies würden Sie in UIViewController aufrufen .

@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

Um den Code zu verwenden, rufen Sie einfach auf [UIApplication currentSize] . Außerdem habe ich den obigen Code ausgeführt, damit ich weiß, dass er funktioniert, und die richtigen Antworten in allen Ausrichtungen zurückgemeldet. Beachten Sie, dass ich die Statusleiste berücksichtige. Interessanterweise musste ich den MIN von der Höhe und Breite der Statusleiste abziehen.

Hoffe das hilft. : D.

Andere Gedanken

Sie können die Abmessungen ermitteln, indem Sie sich die UIWindow- rootViewControllerEigenschaft ansehen . Ich habe mir das in der Vergangenheit angesehen und es werden auf ähnliche Weise sowohl im Hoch- als auch im Querformat die gleichen Abmessungen angezeigt, außer dass eine Rotationstransformation gemeldet wird:

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

<UILayoutContainerView: 0xf7296f0; Rahmen = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; Autoresize = W + H; Layer = <CALayer: 0xf729b80 >>

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

<UILayoutContainerView: 0xf7296f0; Rahmen = (0 0; 320 480); Autoresize = W + H; Layer = <CALayer: 0xf729b80 >>

Sie sind sich nicht sicher, wie Ihre App funktioniert, aber wenn Sie keinen Navigationscontroller verwenden, können Sie unter Ihrer Hauptansicht eine UIView mit der maximalen Höhe / Breite des übergeordneten Elements haben und mit dem übergeordneten Element wachsen / schrumpfen. Dann könnten Sie tun:[[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame] . Das sieht in einer Zeile ziemlich intensiv aus, aber man kommt auf die Idee.

Allerdings ... Es wäre immer noch besser, die obigen 3 Schritte unter der Zusammenfassung auszuführen. Wenn Sie anfangen, mit UIWindows herumzuspielen, werden Sie seltsame Dinge herausfinden, wie das Anzeigen einer UIAlertView, die das Schlüsselfenster von UIApplication so ändert, dass es auf ein neues UIWindow zeigt, das von UIAlertView erstellt wurde. Wer wusste? Ich habe es getan, nachdem ich einen Fehler gefunden hatte, der sich auf keyWindow stützte und herausfand, dass es sich so geändert hatte!

Sam
quelle
5
Dies scheint eine so elementare Aufgabe zu sein, dass ich Probleme habe zu glauben, dass ich meinen eigenen Code hacken muss, um so etwas zu bestimmen.
MusiGenesis
2
Ich werde eine andere Lösung ausprobieren und erneut posten, wenn es funktioniert. Diese Seite ist so aggressiv, wenn Sie nicht schnell antworten, können Sie auch gar nicht antworten. haha ...: Ich hoffe meine Antwort ist zumindest hilfreich. Ich werde wieder ganz schnell etwas anderes ausprobieren.
Sam
1
Toll! (Übrigens, man hat sein Interesse geweckt) :-)
Vamos
1
Wenn Sie applicationFrameanstelle von bounds(auf UIScreen) verwenden, müssen Sie die Höhe der Statusleiste nicht subtrahieren.
Aopsfan
2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size ist ab iOS 8 orientierungsabhängig geworden
Gerald
39

Dies ist mein Lösungscode! Diese Methode kann zur Kategorie Categroy der NSObject-Klasse hinzugefügt werden, oder Sie können eine benutzerdefinierte Top-UIViewController-Klasse definieren und alle Ihre anderen UIViewController diese erben lassen.

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

Beachten Sie nach IOS8, wie in der Eigenschaft "Bound" von Apple Document of UIScreen angegeben :

Diskussion

Dieses Rechteck wird im aktuellen Koordinatenraum angegeben, der alle für das Gerät gültigen Schnittstellenrotationen berücksichtigt. Daher kann sich der Wert dieser Eigenschaft ändern, wenn sich das Gerät zwischen Hoch- und Querformat dreht.

Aus Gründen der Kompatibilität sollten wir daher die IOS-Version erkennen und die folgenden Änderungen vornehmen:

#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
quelle
Ziemlich genau wie meine Antwort, es fehlt nur, wenn es in Portrait verkehrt herum ist. Dies ist nur wichtig, wenn Sie diese Ausrichtung unterstützen.
Robert Wagstaff
2
@Monjer Sie sollten keine Methoden benennen, die keine GET-Anforderung ausführen, denen das Wort get vorangestellt ist. currentScreenBoundsDependOnOrientation ist ein besserer Name für die Methode
bogen
1
@ Hakonbogen.yes kann sein, dass Sie Recht haben, da die "Peroperty" -Deklaration automatisch eine Setter / Getter-Methode generiert. Dies kann zu Namenskonflikten führen und gegen die Namenskonventionen von objc verstoßen. Vielen Dank für Ihren Rat.
Monjer
Es ist schön, dass Apple endlich stillschweigend anerkannt hat, dass ihr Rotationscode ein komplettes Durcheinander war, und uns gerade erzählt hat, wie die verdammten Dimensionen in der aktuellen Ausrichtung sind. Schade, dass es bis Version 8 gedauert hat, um dorthin zu gelangen.
MusiGenesis
30

Hier ist ein praktisches Makro:

#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
quelle
14

In iOS 8+ sollten Sie die folgende viewWillTransitionToSize:withTransitionCoordinatorMethode verwenden:

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

Dies ersetzt die veraltete Animationsmethode, die keine Informationen zur Größe lieferte:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
Mark Hennings
quelle
Dies sollte die akzeptierte Antwort sein. Modern und aktuell.
SarpErdag
Verwenden Sie diese Antwort für iOS 8 und höher.
iPhoneDeveloper
10

Ab iOS 8 werden die Bildschirmgrenzen jetzt korrekt für die aktuelle Ausrichtung zurückgegeben. Dies bedeutet, dass ein iPad im Querformat [UIScreen mainScreen] .bounds unter iOS <= 7 768 und unter iOS 8 1024 zurückgeben würde.

Im Folgenden wird die korrekte Höhe und Breite für alle freigegebenen Versionen zurückgegeben.

-(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
quelle
8

Wenn Sie die orientierungsabhängige Größe wünschen und eine Ansicht haben, können Sie einfach Folgendes verwenden:

view.bounds.size
Tod
quelle
GROSSARTIG! KISS Lösung = Halten Sie es einfach und dumm
bsorrentino
3
KISS bedeutet nicht "Halte es einfach und dumm" - LOL! Es bedeutet "Halte es einfach, dumm!" :-)
Erik van der Neut
Diese Antwort funktioniert natürlich nur, wenn bekannt ist, dass Ihre Ansicht genau im Vollbildmodus angezeigt wird. Aber wenn dies der Fall wäre, hätten Sie wahrscheinlich nicht das ursprüngliche Problem, das vom OP veröffentlicht wurde.
Erik van der Neut
5

Ich habe eine Kategorie für geschrieben UIScreen, die auf allen iOS-Versionen funktioniert, sodass Sie sie folgendermaßen verwenden können :
[[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
quelle
1
Das scheint mir die sauberste Antwort zu sein. Up-Voted.
Erik van der Neut
5

Hier ist ein schneller Weg, um orientierungsabhängige Bildschirmgrößen zu erhalten:

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
}

Diese sind als Standardfunktion in einem meiner Projekte enthalten:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
quelle
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
quelle
0

Unter 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
quelle
0

Verwenden Sie -> setNeedsDisplay () für die Ansicht, deren Größe Sie ändern möchten.

Santosh
quelle