Bagaimana cara mendapatkan tinggi dan lebar layar yang bergantung pada orientasi?

96

Saya mencoba untuk menentukan tinggi dan lebar aplikasi saya saat ini secara terprogram. Saya menggunakan ini:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Tapi ini menghasilkan lebar 320 dan tinggi 480, terlepas dari apakah perangkat dalam orientasi potret atau lanskap. Bagaimana saya bisa menentukan saat lebar dan tinggi (yaitu tergantung pada orientasi perangkat) dari layar utama saya?

MusiGenesis
sumber

Jawaban:

164

Anda dapat menggunakan sesuatu seperti UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)untuk menentukan orientasi dan kemudian menggunakan dimensi yang sesuai.

NAMUN, selama perubahan orientasi seperti di UIViewController

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

Gunakan orientasi yang diteruskan toInterfaceOrientationkarena statusBarOrientation UIApplication masih akan mengarah ke orientasi lama karena belum berubah (karena Anda berada di dalam willpengendali kejadian).

Ringkasan

Ada beberapa postingan terkait ini, tetapi masing-masing sepertinya menunjukkan bahwa Anda harus:

  1. Lihat [[UIScreen mainScreen] bounds]untuk mendapatkan dimensinya,
  2. Periksa orientasi Anda saat ini, dan
  3. Akun untuk tinggi bilah status (jika ditampilkan)

Tautan

Kode Kerja

Saya biasanya tidak melangkah sejauh ini, tetapi Anda membuat saya tertarik. Kode berikut harus melakukan triknya. Saya menulis Kategori di UIApplication. Saya menambahkan metode kelas untuk mendapatkan currentSize atau ukuran dalam orientasi tertentu, yang akan Anda panggil di 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

Untuk menggunakan kode panggilan sederhana [UIApplication currentSize]. Juga, saya menjalankan kode di atas, jadi saya tahu itu berfungsi dan melaporkan kembali tanggapan yang benar di semua orientasi. Perhatikan bahwa saya memperhitungkan bilah status. Menariknya, saya harus mengurangi MIN dari tinggi dan lebar bilah status.

Semoga ini membantu. : D

Pikiran lain

Anda bisa mendapatkan dimensi dengan melihat rootViewControllerproperti UIWindow . Saya telah melihat ini di masa lalu dan itu juga melaporkan dimensi yang sama baik dalam potret maupun lanskap kecuali itu melaporkan memiliki transformasi bergilir:

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

<UILayoutContainerView: 0xf7296f0; bingkai = (0 0; 320 480); transformasi = [0, -1, 1, 0, 0, 0]; ukuran otomatis = W + H; layer = <CALayer: 0xf729b80 >>

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

<UILayoutContainerView: 0xf7296f0; bingkai = (0 0; 320 480); ukuran otomatis = W + H; layer = <CALayer: 0xf729b80 >>

Tidak yakin bagaimana aplikasi Anda bekerja, tetapi jika Anda tidak menggunakan semacam pengontrol navigasi, Anda dapat memiliki UIView di bawah tampilan utama Anda dengan tinggi / lebar maksimum induk dan tumbuh / menyusut dengan induk. Maka Anda bisa melakukan: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]. Itu terlihat cukup intens di satu baris, tetapi Anda mengerti.

Namun ... Akan lebih baik jika melakukan 3 langkah di atas di bawah ringkasan. Mulailah mengotak-atik UIWindows dan Anda akan menemukan hal-hal aneh, seperti menampilkan UIAlertView akan mengubah keywindow UIApplication untuk menunjuk ke UIWindow baru yang dibuat oleh UIAlertView. Siapa yang tahu? Saya melakukannya setelah menemukan bug yang mengandalkan keyWindow dan menemukan bahwa itu berubah seperti itu!

Sam
sumber
5
Ini sepertinya tugas dasar sehingga saya kesulitan percaya bahwa saya harus meretas kode saya sendiri untuk menentukan sesuatu seperti ini.
MusiGenesis
2
Saya akan mencoba solusi lain dan memposting ulang jika berhasil. Situs ini sangat agresif jika Anda tidak menjawab dengan cepat, Anda mungkin juga tidak menjawab sama sekali. haha ...: Saya harap jawaban saya setidaknya membantu. Sekali lagi, saya akan mencoba sesuatu yang lain dengan sangat cepat.
Sam
1
Bagus! (BTW, seseorang memiliki minat yang terusik) :-)
Vamos
1
Jika Anda menggunakan applicationFramealih-alih bounds(di UIScreen), Anda tidak perlu mengurangi tinggi bilah status.
aopsfan
2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size telah menjadi orientasi tergantung dari iOS 8 dan seterusnya
Gerald
39

Ini adalah kode solusi saya! Metode ini dapat ditambahkan ke Categroy kelas NSObject, atau Anda dapat menentukan kelas UIViewController kustom Teratas, dan membiarkan semua UIViewController Anda yang lain untuk mewarisinya.

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

Perhatikan , setelah IOS8, karena Dokumen Apple dari properti batas UIScreen mengatakan:

Diskusi

Persegi panjang ini ditentukan dalam ruang koordinat saat ini, yang memperhitungkan setiap rotasi antarmuka yang berlaku untuk perangkat. Oleh karena itu, nilai properti ini dapat berubah saat perangkat berputar antara orientasi potret dan lanskap.

jadi untuk pertimbangan kompatibilitas, sebaiknya kita mendeteksi versi IOS dan melakukan perubahan seperti di bawah ini:

#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
sumber
Hampir sama dengan jawaban saya, satu-satunya hal yang terlewatkan adalah jika dalam Potret terbalik. Ini hanya penting jika Anda mendukung orientasi itu.
Robert Wagstaff
2
@Monjer Anda tidak boleh menyebutkan metode yang tidak menjalankan permintaan GET, diawali dengan kata get. currentScreenBoundsDependOnOrientation adalah nama yang lebih baik untuk metode ini
bogen
1
@ Hakonbogen.yes mungkin Anda benar, karena pernyataan "peroperty" secara otomatis menghasilkan metode penyetel / pengambil, dan ini dapat menyebabkan konflik penamaan, dan bertentangan dengan konvensi penamaan objc. Terima kasih atas saran Anda.
monjer
Sangat menyenangkan bahwa Apple akhirnya secara diam-diam mengakui bahwa kode rotasi mereka benar-benar berantakan, dan baru saja mulai memberi tahu kami apa dimensi sialan itu dalam orientasi saat ini. Sayang sekali butuh waktu hingga versi 8 untuk sampai ke sana.
MusiGenesis
30

Berikut makro yang berguna:

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

Di iOS 8+ Anda harus menggunakan viewWillTransitionToSize:withTransitionCoordinatormetode:

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

Ini menggantikan metode animasi yang tidak digunakan lagi yang tidak memberikan informasi tentang ukuran:

-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
Mark Hennings
sumber
Ini harus menjadi jawaban yang diterima. Modern dan up to date.
SarpErdag
Gunakan jawaban ini untuk ios 8 ke atas.
iPhoneDeveloper
10

Pada batas layar iOS 8 sekarang dikembalikan dengan benar untuk orientasi saat ini. Ini berarti iPad dalam orientasi lanskap [UIScreen mainScreen]. Batas akan menghasilkan 768 pada iOS <= 7 dan 1024 pada iOS 8.

Gambar berikut mengembalikan tinggi dan lebar yang benar pada semua versi yang dirilis.

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

jika Anda menginginkan ukuran yang bergantung pada orientasi dan Anda memiliki tampilan, Anda dapat menggunakan:

view.bounds.size
Rubah
sumber
BAGUS! Solusi KISS = Keep It Simple and Stupid
bsorrentino
3
KISS bukan berarti "Tetap Sederhana dan Bodoh" - LOL! Artinya "Tetap sederhana, bodoh!" :-)
Erik van der Neut
Selain itu, jawaban ini jelas hanya berfungsi jika tampilan Anda diketahui benar-benar dalam layar penuh. Tetapi, jika itu masalahnya, maka Anda mungkin tidak memiliki masalah asli yang diposting oleh OP.
Erik van der Neut
5

Saya menulis kategori UIScreen, yang bekerja pada semua versi iOS, sehingga Anda dapat menggunakannya seperti ini:
[[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
sumber
1
Sepertinya ini jawaban terbersih bagiku. Dipilih.
Erik van der Neut
5

Berikut adalah cara cepat untuk mendapatkan ukuran layar yang bergantung pada orientasi:

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
}

Ini termasuk sebagai fungsi standar dalam proyek saya:

https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
sumber
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());
pengguna4082558
sumber
0

Namun, di 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
sumber
0

gunakan -> setNeedsDisplay () untuk tampilan yang ingin Anda ubah ukurannya.

Santosh
sumber