[UIScreen mainScreen] .bounds.size sta diventando dipendente dall'orientamento in iOS8?


184

Ho eseguito il seguente codice in iOS 7 e 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);

Quanto segue è il risultato di iOS 8:

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

Confronto con il risultato in iOS 7:

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

Esiste una documentazione che specifica questa modifica? O è un bug temporaneo nelle API di iOS 8?


13
Bene, l'output di iOS8 sembra molto più logico
Levi,

Risposte:


173

Sì, dipende da orientamento in iOS8, non un bug. È possibile rivedere la sessione 214 del WWDC 2014 per ulteriori informazioni: "Visualizza i progressi del controller in iOS 8"

Citazione dalla presentazione:

UIScreen è ora orientato all'interfaccia:

  • [UIScreen bounds] ora orientato all'interfaccia
  • [UIScreen applicationFrame] ora orientato all'interfaccia
  • Le notifiche dei frame della barra di stato sono orientate all'interfaccia
  • Le notifiche dei frame della tastiera sono orientate all'interfaccia

7
Nella lezione del WWDC menzionata sopra, la parte orientata all'interfaccia inizia alle 51:50.
cnotethegr8,

2
Ho trascorso la maggior parte di oggi cercando di aggirare questo progresso. Apparentemente non succede sempre , quindi se sei uno sviluppatore di un SDK che deve lavorare in altre applicazioni, queste cose sono ancora più complicate.
Glenn Maynard,

1
@aroth non puoi innovare senza frenare alcuni vecchi habbit.
Boris Y.

23
@borisy - Rispetto rispettosamente. Nella maggior parte dei casi è possibile innovare preservando la compatibilità con le versioni precedenti. Secondo me, la rottura dei cambiamenti è più che altro pigrizia. Vogliono che tutti gli altri facciano il lavoro.
aroth

1
Questa risposta sarebbe ancora più utile se fosse spiegato cosa significa realmente orientato all'interfaccia . Potrei sbagliarmi, ma penso che la dipendenza dall'orientamento riguardi solo la visualizzazione dei controller. Se prendi un'altra classe e calcoli i limiti, sono ancora secondo il vecchio stile, sempre in verticale.
Maxi Mus,

59

Sì, dipende dall'orientamento in iOS8.

Ho scritto un metodo Util per risolvere questo problema per le app che devono supportare versioni precedenti 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
Ho modificato il codice, per favore controlla, la tua condizione per controllare la versione del sistema operativo era sbagliata
Jageen,

@Jageen Per favore, chiarisci, il controllo della versione funziona per me. Qual è il problema?
cbartel,

Quello che capisco è che dobbiamo cambiare altezza e larghezza se il sistema operativo è iOS8 e l'orientamento è orizzontale, ho ragione?
Jageen,

@Jageen Negative, in iOS 8 il metodo dipende dall'orientamento. La tua logica è cambiata. La tua modifica è stata correttamente respinta.
cbartel,

@cbartel c'è un modo per classificare questo in UIScreen in modo che la nostra chiamata originale a [UIScreen mainScreen] .bounds.size funzionerà sia per iOS 7 che iOS 8?
Kevin

34

Sì, infatti, la dimensione dello schermo ora dipende dall'orientamento in iOS 8. A volte, tuttavia, si desidera ottenere una dimensione fissata all'orientamento verticale. Ecco come lo faccio.

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

    if ([screen respondsToSelector:@selector(fixedCoordinateSpace)]) {
                    return [screen.coordinateSpace convertRect:screen.bounds toCoordinateSpace:screen.fixedCoordinateSpace];
    } 
    return screen.bounds;
}

2
Sto scoprendo che questo risolve il problema con le normali app per iPhone, ma non con le app per iPhone in esecuzione su iPad.
ThomasW

32

Sì, ora dipende dall'orientamento.

Preferisco il metodo seguente per ottenere le dimensioni dello schermo in modo indipendente dall'orientamento rispetto ad alcune delle risposte sopra, sia perché è più semplice sia perché non dipende da nessuno dei codici di orientamento (il cui stato può dipendere dal volta che vengono chiamati) o al controllo della versione. È possibile che si desideri il nuovo comportamento di iOS 8, ma funzionerà se è necessario che sia stabile su tutte le versioni di iOS.

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

Probabilmente non funzionerà su qualcosa come Apple TV, dove è (quasi) sempre più largo di quanto sia alto.
cbh2000,

11

In relazione a questa domanda poiché ha risolto il mio problema, qui due definizioni che uso per i calcoli della larghezza e dell'altezza dello schermo:

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

Se stai supportando sia iOS 7 che iOS 8, questa è la soluzione migliore per questo problema.


@Namit Gupta, la tua modifica è sbagliata. Se la versione IOS è 8 o successiva, possiamo usare le dimensioni UIScreen poiché dipendono dall'orientamento. Prima di iOS 8 dovevi verificare l'orientamento della barra di stato. La tua modifica ora sta dicendo che tutte le versioni di iOS non inferiori a 8 dovrebbero controllare la barra di stato, che è sbagliata.
Antoine,

9

Puoi usare nativeBounds(indipendente dall'orientamento)

nativeBounds

Il rettangolo di delimitazione dello schermo fisico, misurato in pixel. (sola lettura)

Dichiarazione SWIFT

  var nativeBounds: CGRect { get }

Questo rettangolo si basa sul dispositivo con orientamento verticale. Questo valore non cambia quando il dispositivo ruota.

Rilevamento dell'altezza del dispositivo:

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

}

Rilevamento della larghezza del dispositivo:

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

}

3
Tieni presente che questo metodo restituisce pixel, mentre la maggior parte degli altri metodi si occupa dei punti. Cose molto diverse.
jcsahnwaldt Reinstate Monica,

1
Nel mio caso esattamente quello di cui avevo bisogno :) (OpenGL o altre viste non basate su UIVview ma dove ho bisogno di conoscere le dimensioni esatte dei pixel)
Bersaelor

3
Attenzione: su iPhone 6+ questo ha restituito 1080 x 1920 che potrebbe non essere quello che vuoi
Chanon,

8

Non è un bug nell'SDK di iOS 8. Hanno reso dipendente l'orientamento dell'interfaccia. In base alla tua domanda su qualche riferimento o documentazione a tale fatto, ti consiglio vivamente di guardarlo durante View Controller Advancements in iOS 8la sessione del WWDC 2014 . La parte più interessante (secondo i tuoi dubbi) è Screen Coordinatesche inizia alle 50:45.


5

Sì, dipende dall'orientamento in iOS8.

Ecco come puoi avere un modo conciso di leggere i limiti in modo iOS 8 su SDK e versioni del sistema operativo.

#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
Controllare anche la versione dell'SDK è un buon consiglio nel caso in cui i colleghi stiano costruendo la tua app con versioni diverse dell'SDK (anche se ciò non dovrebbe accadere!).
Craig McMahon,

4

La mia soluzione è una combinazione di MaxK e hfossli. Ho creato questo metodo su una categoria di UIScreen e non ha controlli di versione (che è una cattiva pratica):

//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

Avevo bisogno di una funzione di supporto rapido che mantenesse lo stesso comportamento di iOS7 su iOS8 - questo mi permetteva di scambiare le mie [[UIScreen mainScreen] bounds]chiamate e non toccare altri codici ...

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

Cattivo, ma ottiene il lavoro fatto fino a quando il tempo non può essere messo a sistemare le cose correttamente :-)
DuneCat

3

Il metodo seguente può essere utilizzato per trovare i limiti dello schermo per un determinato orientamento, indipendentemente dalla versione di iOS. Questo metodo restituirà i limiti in base alle dimensioni dello schermo del dispositivo e fornirà lo stesso valore CGRect indipendentemente dalla versione di 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

Questo è quello che ho usato per calcolare il retto corretto:

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

Basta aggiungere la versione rapida di un'eccellente funzione cbartel con risposta sopra.

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

Il mio problema era legato al frame UIWindows che stava andando in negativo. Così fatto il codice come sotto in 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)];

E il suo lavoro per me lo prova.


1

iOS 8 o superiore

Una soluzione per coloro che vogliono scoprire la dimensione dello schermo in punti (lo schermo da 3,5 pollici ha 320 × 480 punti, lo schermo da 4,0 pollici ha 320 × 568 punti, ecc.) Sarebbe

- (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 che ho notato è che l' ordine degli orientamenti di interfaccia supportati in Info.plist è importante. Ho riscontrato il problema di questa domanda con la mia app (che fa l'orientamento nel codice), ma non ho specificato da nessuna parte che l'orientamento predefinito è Verticale.

In ogni caso, ho pensato che l'orientamento predefinito fosse Ritratto.

Riorganizzare itens in Info.plist, mettere Portrait in primo piano, ripristinare il comportamento previsto.


0

Questo darà corretto dispositivo in iOS7 e iOS 8 entrambi,

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

// Puoi aggiungere anche più dispositivi (ieiPad).


La domanda non riguarda il riconoscimento del dispositivo in base alla risoluzione dello schermo. Inoltre, Apple consiglia di creare un'interfaccia utente adattiva basata su classi di dimensioni non sul rilevamento di dispositivi / schermi
Julian Król,

0

Ha usato la soluzione di mnemia leggermente modificata, quella senza controllo della versione di iOS, usando min / max sui limiti dello schermo principale.
Avevo bisogno di un CGRectcosì ottenuto CGRectdal limite principale Pagina principale e cambiato size.width=min(w,h), size.height=max(w,h). Quindi ho chiamato la CGRectfunzione get indipendente dal sistema operativo in due punti del mio codice, dove ho dimensioni dello schermo OpenGL, tocchi, ecc. Prima della correzione avevo 2 problemi - su IOS 8.x in modalità orizzontale la posizione di OpenGLvisualizzazione della visualizzazione era errata: 1 / 4 a schermo intero nella parte inferiore sinistra. E i secondi tocchi hanno restituito valori non validi. Entrambi i problemi sono stati risolti come spiegato. Grazie!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.