Ekranın yönüne bağlı yüksekliği ve genişliği nasıl elde edilir?


96

Uygulamamın mevcut yüksekliğini ve genişliğini programlı olarak belirlemeye çalışıyorum. Bunu kullanıyorum:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Ancak bu, aygıtın dikey veya yatay yönde olmasına bakılmaksızın, 320'lik bir genişlik ve 480'lik bir yükseklik sağlar. Ana ekranımın mevcut genişliğini ve yüksekliğini (yani cihaz yönüne bağlı olarak) nasıl belirleyebilirim?

Yanıtlar:


164

UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)Yönlendirmeyi belirlemek gibi bir şey kullanabilir ve ardından boyutları buna göre kullanabilirsiniz.

ANCAK, UIViewController'daki gibi bir yönelim değişikliği sırasında

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

toInterfaceOrientationUIApplication'ın statusBarOrientation öğesi, henüz değişmediği için (bir willolay işleyicisinin içinde olduğunuzdan) eski yönlendirmeyi göstermeye devam edeceğinden, iletilen yönlendirmeyi kullanın .

Özet

Bununla ilgili birkaç gönderi var, ancak her biri yapmanız gerektiğini gösteriyor gibi görünüyor:

  1. [[UIScreen mainScreen] bounds]Boyutları almak için bakın ,
  2. Hangi yönelimde olduğunuzu kontrol edin ve
  3. Durum çubuğu yüksekliğini hesaba katın (gösteriliyorsa)

Bağlantılar

Çalışma Kodu

Genelde bu kadar ileri gitmem ama ilgimi çektin. Aşağıdaki kod hile yapmalıdır. UIApplication üzerine bir Kategori yazdım. Belirli bir yönelimde currentSize veya boyutu elde etmek için sınıf yöntemleri ekledim, UIViewController'da bunu çağırırdınız 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

Kodu kullanmak için basit arama [UIApplication currentSize]. Ayrıca, yukarıdaki kodu çalıştırdım, bu yüzden çalıştığını biliyorum ve tüm yönlerde doğru yanıtları geri bildiriyorum. Durum çubuğunu hesaba kattığımı unutmayın. İlginç bir şekilde, durum çubuğunun yükseklik ve genişliğinin MIN değerini çıkarmak zorunda kaldım.

Bu yardımcı olur umarım. : D

Diğer düşünceler

UIWindow'un rootViewControllerözelliğine bakarak boyutları almaya gidebilirsiniz . Geçmişte buna baktım ve aynı boyutları hem dikey hem de yatay olarak rapor ediyor, tek farkı bir döndürme dönüşümü olduğunu bildiriyor:

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] görünümü]

<UILayoutContainerView: 0xf7296f0; çerçeve = (0 0; 320 480); dönüşüm = [0, -1, 1, 0, 0, 0]; otomatik yeniden boyutlandırma = W + H; katman = <CALayer: 0xf729b80 >>

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] görünümü]

<UILayoutContainerView: 0xf7296f0; çerçeve = (0 0; 320 480); otomatik yeniden boyutlandırma = W + H; katman = <CALayer: 0xf729b80 >>

Uygulamanızın nasıl çalıştığından emin değilim, ancak bir tür gezinme denetleyicisi kullanmıyorsanız, ana görünümünüzün altında ebeveynin maksimum yüksekliği / genişliğine sahip ve ebeveynle birlikte büyür / küçülür. Sonra yapabilirdi: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]. Bu bir satırda oldukça yoğun görünüyor, ama fikri anladınız.

Ancak ... Yukarıdaki 3 adımı özetin altında yapmak yine de daha iyi olacaktır. UIWindows ile uğraşmaya başlayın ve bir UIAlertView göstermek gibi garip şeyler keşfedeceksiniz, UIApplication'ın anahtar penceresini UIAlertView'ın oluşturduğu yeni bir UIWindow'a işaret edecek şekilde değiştirecek. Kim biliyordu? KeyWindow'a güvenerek bir hata bulup bunun böyle değiştiğini keşfettikten sonra yaptım!


5
Bu o kadar basit bir görev gibi görünüyor ki, böyle bir şeyi belirlemek için kendi kodumu kırmam gerektiğine inanmakta güçlük çekiyorum.
MusiGenesis

2
Başka bir çözüm deneyeceğim ve işe yararsa yeniden göndereceğim. Bu site o kadar agresif ki, hızlı cevap vermezsen, hiç cevap vermeyebilirsin. haha ...: DI umarım cevabım en azından yardımcı olur. Yine, hızlı bir şekilde başka bir şey deneyeceğim.
Sam

1
Harika! (BTW, birinin faizi kesilir) :-)
Vamos

1
(UIScreen'de) applicationFrameyerine kullanırsanız bounds, durum çubuğu yüksekliğini çıkarmanız gerekmez.
aopsfan

2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size , iOS 8'den itibaren yönelim bağımlı hale geldi
Gerald,

39

Bu benim çözüm kodum! Bu yöntem NSObject sınıfının Categroy'una ekleyebilir veya bir Üst özel UIViewController sınıfı tanımlayabilir ve diğer tüm UIViewControllers'larınızın onu devralmasına izin verebilirsiniz.

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

Not iOS8 sonra, sıra, UIScreen en sınırları özelliğinin Apple Belgesi diyor ki:

Tartışma

Bu dikdörtgen, cihaz için geçerli olan herhangi bir arayüz rotasyonunu hesaba katan mevcut koordinat alanında belirtilir. Bu nedenle, cihaz dikey ve yatay yönler arasında döndüğünde bu özelliğin değeri değişebilir.

bu nedenle uyumluluğun değerlendirilmesi için IOS sürümünü tespit etmeli ve aşağıdaki gibi değişikliği yapmalıyız:

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

Cevabımla hemen hemen aynı, gözden kaçırdığı tek şey Portre'nin baş aşağı olması. Bu sadece o yönelimi desteklerseniz önemlidir.
Robert Wagstaff

2
@Monjer, bir GET isteği gerçekleştirmeyen yöntemleri, get kelimesinin önüne i olarak adlandırmamalısınız. currentScreenBoundsDependOnOrientation, yöntem için daha iyi bir addır
bogen

1
@ Hakonbogen.yes haklı olabilirsiniz, çünkü "peroperty" bildirimi otomatik olarak ayarlayıcı / alıcı yöntemini oluşturur ve bu, adlandırma çatışmasına neden olabilir ve objc adlandırma kurallarına aykırı olabilir. Tavsiyeniz için teşekkürler.
monjer

Apple'ın, rotasyon kodlarının tam bir karmaşa olduğunu nihayet zımnen kabul etmesi ve bize şu anki yönelimdeki lanet boyutların ne olduğunu anlatmaya başlaması çok güzel. Sürüm 8'in oraya ulaşması çok kötü oldu.
MusiGenesis

31

İşte kullanışlı bir 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)

14

İOS 8+ için şu viewWillTransitionToSize:withTransitionCoordinatoryöntemi kullanmalısınız :

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

Bu, boyut hakkında hiçbir bilgi vermeyen kullanımdan kaldırılmış animasyon yönteminin yerini alır:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration

Kabul edilen cevap bu olmalıdır. Modern ve güncel.
SarpErdag

Bu yanıtı ios 8 ve üstü için kullanın.
iPhoneDeveloper

10

İOS 8'den itibaren ekran sınırları artık geçerli yön için doğru şekilde döndürülüyor. Bu, yatay yöndeki bir iPad [UIScreen mainScreen] .bounds'un iOS <= 7 ve 1024'te iOS 8'de 768 döndüreceği anlamına gelir.

Aşağıdakiler, yayınlanan tüm sürümlerde doğru yüksekliği ve genişliği döndürür.

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

8

yönlendirmeye bağlı boyutu istiyorsanız ve bir görünümünüz varsa, sadece şunları kullanabilirsiniz:

view.bounds.size

HARİKA! KISS çözümü = Basit ve Aptal
Olun

3
KISS "Basit ve Aptal Olsun" anlamına gelmez - LOL! "Basit tut, aptal!" Demek. :-)
Erik van der Neut

Ayrıca, bu yanıt tabii ki yalnızca görünümünüzün tam ekran olduğu biliniyorsa işe yarar. Ancak, durum böyleyse, muhtemelen OP tarafından yayınlanan orijinal soruna sahip değilsinizdir.
Erik van der Neut

5

Ben kategorisini yazdım UIScreentüm iOS sürümlerinde çalışır, bu gibi kullanabilirsiniz, böylece,:
[[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

1
Bu bana en temiz cevap gibi görünüyor. Yukarı oy verildi.
Erik van der Neut

5

Yönlendirmeye bağlı ekran boyutlarını almanın hızlı bir yolu:

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
}

Bunlar benim bir projemde standart bir işlev olarak yer alıyor:

https://github.com/goktugyil/EZSwiftExtensions


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

0

Ancak iOS 8.0.2'de:

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

0

Yeniden boyutlandırmak istediğiniz görünüm için -> setNeedsDisplay () öğesini kullanın.

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.