[UIScreen mainScreen] .bounds.size, iOS8'de yönlendirmeye bağımlı mı?


184

Hem iOS 7 hem de iOS 8'de aşağıdaki kodu çalıştırdım:

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

Aşağıdakiler iOS 8'in sonucudur:

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

İOS 7'deki sonuçla karşılaştırıldığında:

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

Bu değişikliği belirten herhangi bir belge var mı? Yoksa iOS 8 API'larında geçici bir hata mı?


13
İOS8 çıkışı çok daha mantıklı görünüyor
Levi

Yanıtlar:


173

Evet, iOS8'de yönlendirmeye bağlı, bir hataya değil. Daha fazla bilgi için WWDC 2014 oturum 214'u inceleyebilirsiniz: "iOS 8'deki Denetleyici Geliştirmelerini Görüntüle"

Sunumdan alıntı:

UIScreen artık arayüz odaklı:

  • [UIScreen sınırları] artık arayüz odaklı
  • [UIScreen applicationFrame] artık arayüz odaklı
  • Durum çubuğu çerçevesi bildirimleri arabirime yöneliktir
  • Klavye çerçevesi bildirimleri arayüz odaklı

7
Yukarıda belirtilen WWDC dersinde, arayüz odaklı bölüm 51: 50'de başlar.
cnotethegr8

2
Bugünün çoğunu bu ilerleme üzerinde çalışmak için harcadım. Görünüşe göre her zaman olmaz, bu yüzden başka uygulamalarda çalışması gereken bir SDK geliştiricisi iseniz, bu şeyler daha da karmaşıklaştı.
Glenn Maynard

1
@aroth bazı eski alışkanlıkları frenlemeden yenilik yapamazsınız.
Boris Y.

23
@borisy - Ben saygıyla katılmıyorum. Çoğu durumda geriye dönük uyumluluğu korurken yenilik yapmak mümkündür. Değişikliklerin kırılması bence tembellikten başka her şeyden daha fazla. Herkesin işi yapmasını istiyorlar .
aroth

1
Arayüz odaklı gerçekte ne anlama geldiği açıklanırsa, bu cevap daha da yararlı olacaktır . Yanılıyor olabilirim, ama bence yönelim bağımlılığı sadece kontrolörlerle ilgilidir. Başka bir sınıf alır ve sınırları hesaplarsanız, hala eski stile göre, her zaman portre.
Maxi Muş

59

Evet, iOS8'de yönlendirmeye bağlı.

İşletim sisteminin eski sürümlerini desteklemesi gereken uygulamalar için bu sorunu çözmek için bir Util yöntemi yazdım.

+ (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
Kodu düzenledim lütfen kontrol edin, işletim sistemi sürümünü kontrol etme durumunuz yanlıştı
Jageen

@Jageen Lütfen açıklayın, sürüm kontrolü benim için çalışıyor. Sorun nedir?
cbartel

Anladığım şey, işletim sistemi iOS8 ve yönelim Yatay ise yükseklik ve genişliği değiştirmemiz gerekiyor, doğru mu?
Jageen

@Jageen Negatif, iOS 8'de yöntem yönlendirmeye bağlıdır. Mantığınız değiştirildi. Yaptığınız düzenleme doğru bir şekilde reddedildi.
cbartel

@cbartel [UIScreen mainScreen] .bounds.size'ye yaptığımız orijinal çağrı hem iOS 7 hem de iOS 8 için çalışacak şekilde bunu UIScreen'de sınıflandırmanın bir yolu var mı?
kevinl

34

Evet, aslında, ekran boyutu şimdi iOS 8'de yönlendirmeye bağlı. Bazen, dikey yönlendirmeye sabit bir boyut elde etmek isteniyor. İşte böyle yapıyorum.

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

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

2
Bunun normal iPhone uygulamalarıyla sorunu çözdüğünü, ancak iPad'de çalışan iPhone uygulamalarıyla çözmediğini görüyorum.
ThomasW

32

Evet, şimdi yönlendirmeye bağlı.

Yukarıdaki yöntemi bazı cevaplara yönlendirme bağımsız bir şekilde elde etmek için aşağıdaki yöntemi tercih ediyorum, çünkü hem daha basit hem de yönlendirme kodunun herhangi birine bağlı olmadığı için (durumu çağrıldıklarında) veya sürüm kontrolünde. Yeni iOS 8 davranışını isteyebilirsiniz, ancak iOS'un tüm sürümlerinde kararlı olması gerekiyorsa bu işe yarayacaktır.

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

Muhtemelen Apple TV gibi bir şey üzerinde çalışmayacaktır, (neredeyse) her zaman uzunluğundan daha geniştir.
cbh2000

11

Sorunumu çözdüğü için bu soru ile ilgili olarak, burada ekran genişliği ve yükseklik hesaplamaları için kullandığım iki tanım var:

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

Hem iOS 7 hem de iOS 8'i destekliyorsanız, bu sorun için en iyi çözüm budur.


@Namit Gupta, düzenlemen yanlış. IOS sürümü 8 veya üzeriyse, yönlendirmeye bağlı olduğundan UIScreen boyutlarını kullanabiliriz. İOS 8'den önce durum çubuğu yönünü kontrol etmeniz gerekiyordu. Yaptığınız düzenleme şimdi 8'den düşük olmayan tüm iOS sürümlerinin durum yönlendirmesini kontrol etmesi gerektiğini söylüyor, bu da yanlış.
Antoine

9

Kullanabilirsiniz nativeBounds (yönelimden bağımsız)

nativeBounds

Fiziksel ekranın piksel cinsinden ölçülen sınırlayıcı dikdörtgeni. (Sadece oku)

Beyan SWIFT

  var nativeBounds: CGRect { get }

Bu dikdörtgen cihaza dikey olarak yerleştirilir. Bu değer cihaz döndükçe değişmez.

Cihazın yüksekliğini algılama:

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

}

Cihazın genişliğini algılama:

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

}

3
Diğer yöntemlerin çoğu noktalarla ilgilenirken, bu yöntemin piksel döndürdüğünü unutmayın. Çok farklı şeyler.
jcsahnwaldt Reinstate Monica

1
Benim durumumda tam olarak ihtiyacım olan şey :) (OpenGL veya UIViews'e dayanmayan ancak tam piksel boyutlarını bilmem gereken yere göre diğer Görünümler)
Bersaelor

3
Uyarı: iphone 6+ üzerinde bu, istediğiniz gibi olmayabilir 1080 x 1920 döndürdü
Chanon

8

İOS 8 SDK'da bir hata değil. Sınırların arayüz yönelimini bağlı kıldılar. Bu gerçeğe ilişkin bazı referans veya belgeler hakkındaki sorunuza göre View Controller Advancements in iOS 8, WWDC 2014'ten 214 oturum olduğunu izlemenizi şiddetle tavsiye ederim . En ilginç kısım (şüphelerinize göre) 50 Screen Coordinates:45'te başlıyor.


5

Evet, iOS8'de yönlendirmeye bağlı.

SDK ve OS sürümlerinde iOS 8 tarzında sınırları tutarlı bir şekilde nasıl okuyabileceğiniz aşağıda açıklanmıştır.

#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
SDK sürümünü de kontrol etmek, iş arkadaşlarınızın uygulamanızı SDK'nın farklı sürümleriyle oluşturması durumunda iyi bir ipucudur (bu olmamalı!).
Craig McMahon

4

Benim çözümüm MaxK ve hfossli kombinasyonudur. Bu yöntemi bir UIScreen kategorisinde yaptım ve hiçbir sürüm denetimi (ki bu kötü bir uygulamadır) vardır:

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

İOS8 altında iOS7 ile aynı davranışı koruyan hızlı bir yardımcı fonksiyona ihtiyacım vardı - bu, [[UIScreen mainScreen] bounds]çağrılarımı değiştirmeme ve diğer koda dokunmama izin verdi ...

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

Kötü, ama işleri düzgün sabitleme içine koymak olabilir kadar iş yapılır :-)
DuneCat

3

Aşağıdaki yöntem, iOS sürümünden bağımsız olarak belirli bir yönelim için ekran sınırlarını bulmak için kullanılabilir. Bu yöntem, cihazın ekran boyutuna bağlı olarak sınırları döndürecek ve iOS sürümünden bağımsız olarak aynı CGRect değerini verecektir.

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

Bu doğru rect hesaplamak için kullandığım şey:

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

Sadece yukarıda cevaplanan mükemmel bir cbartel fonksiyonunun hızlı sürümünü eklemek.

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

Benim sorunum eksi gidiş UIWindows çerçeve ile ilgili idi. Bu yüzden MyViewController - (NSUInteger) desteklenenInterfaceOrientations Yöntemi kodu aşağıdaki gibi yapılmış

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

Ve benim için işi denemek.


1

iOS 8 veya üstü

Ekran boyutunu puan olarak bulmak isteyenler için bir çözüm (3,5 inç ekran 320 × 480 puan, 4.0 inç ekran 320 × 568 puan vb.)

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

Belirttiğim bir şey, sipariş , Info.plist'deki desteklenen arayüz yönlerinin önemlidir. (Bu kod yönlendirme yapar) benim app ile bu sorunun sorunu var, ama hiçbir yerde varsayılan yönlendirme dikey olduğunu belirtmedim.

O varsayılan yönelim düşünce oldu her durumda portresi.

Info.plist'deki yinelemeleri yeniden düzenlemek, ilk önce Dikey'i koymak, beklenen davranışı geri yükledi.


0

Bu doğru cihaz verecektir -iOS7 ve iOS8 , hem

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

// Daha fazla cihaz da ekleyebilirsiniz (ieiPad).


Soru, ekran çözünürlüğüne dayalı cihaz tanıma ile ilgili değildir. Ayrıca Apple, cihaz / ekran algılamada olmayan boyut sınıflarına dayanan uyarlanabilir kullanıcı arayüzü oluşturmayı önerir
Julian Król

0

İOS sürüm kontrolü olmayan, ana ekran sınırlarında min / max kullanarak biraz değiştirilmiş mnemia'nın çözümü kullanıldı.
Bir ihtiyaç CGRectyüzden var CGRectMainscreen sınırlarından ve değişti size.width=min(w,h), size.height=max(w,h). Daha sonra CGRectekran boyutunda OpenGL, dokunuşlar vb için ekran kodunu alıyorum , kodumda iki yerde işletim sisteminden bağımsız alma işlevini çağırdım . Düzeltmeden önce 2 sorun yaşadım - yatay modda IOS 8.x'te görüntü konumu OpenGLyanlış: 1 / Sol alt kısımda tam ekran 4. İkinci dokunuş geçersiz değerler döndürdü. Her iki sorun da açıklandığı gibi giderildi. Teşekkürler!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.