จะรับความสูงและความกว้างของหน้าจอได้อย่างไร?


96

ฉันกำลังพยายามกำหนดความสูงและความกว้างปัจจุบันของแอปพลิเคชันโดยใช้โปรแกรม ฉันใช้สิ่งนี้:

CGRect screenRect = [[UIScreen mainScreen] bounds];

แต่จะให้ความกว้าง 320 และความสูง 480 ไม่ว่าอุปกรณ์จะอยู่ในแนวตั้งหรือแนวนอน ฉันจะกำหนดความกว้างและความสูงปัจจุบัน (เช่นขึ้นอยู่กับการวางแนวอุปกรณ์) ของหน้าจอหลักได้อย่างไร?

คำตอบ:


164

คุณสามารถใช้บางอย่างเช่นUIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)เพื่อกำหนดแนวจากนั้นใช้มิติข้อมูลตามนั้น

อย่างไรก็ตามในระหว่างการเปลี่ยนทิศทางเช่นใน UIViewController

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

ใช้การวางแนวที่ส่งผ่านtoInterfaceOrientationเนื่องจาก statusBarOrientation ของ UIApplication จะยังคงชี้ไปที่การวางแนวเดิมเนื่องจากยังไม่มีการเปลี่ยนแปลง (เนื่องจากคุณอยู่ในwillตัวจัดการเหตุการณ์)

สรุป

มีโพสต์ที่เกี่ยวข้องหลายโพสต์ แต่ดูเหมือนว่าแต่ละโพสต์จะระบุว่าคุณต้อง:

  1. ดู[[UIScreen mainScreen] bounds]เพื่อให้ได้ขนาด
  2. ตรวจสอบว่าคุณอยู่ในแนวไหนและ
  3. บัญชีสำหรับความสูงของแถบสถานะ (ถ้าแสดง)

ลิงค์

รหัสการทำงาน

ฉันมักจะไม่ไปไกลขนาดนี้ แต่คุณทำให้ฉันสนใจ รหัสต่อไปนี้ควรทำเคล็ดลับ ฉันเขียนหมวดหมู่ใน UIApplication ฉันจะเพิ่มวิธีการเรียนการรับ currentSize หรือขนาดในแนวรับซึ่งเป็นสิ่งที่คุณจะเรียกใน willRotateToInterfaceOrientation:duration:UIViewController

@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

ในการใช้รหัสโทร[UIApplication currentSize]. นอกจากนี้ฉันรันโค้ดด้านบนดังนั้นฉันจึงรู้ว่ามันใช้งานได้และรายงานกลับคำตอบที่ถูกต้องในทุกทิศทาง โปรดทราบว่าฉันแยกตัวประกอบในแถบสถานะ ที่น่าสนใจคือฉันต้องลบ MIN ของความสูงและความกว้างของแถบสถานะ

หวังว่านี่จะช่วยได้ : ง

ความคิดอื่น ๆ

คุณสามารถรับมิติข้อมูลได้โดยดูที่rootViewControllerคุณสมบัติของ UIWindow ฉันเคยดูสิ่งนี้ในอดีตและรายงานในทำนองเดียวกันว่ามีขนาดเดียวกันทั้งในแนวตั้งและแนวนอนยกเว้นจะรายงานว่ามีการแปลงแบบหมุนเวียน:

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] ดู]

<UILayoutContainerView: 0xf7296f0; เฟรม = (0 0; 320 480); แปลงร่าง = [0, -1, 1, 0, 0, 0]; ปรับขนาดอัตโนมัติ = W + H; เลเยอร์ = <CALayer: 0xf729b80 >>

(gdb) po [[[[UIApplication sharedApplication] keyWindow] rootViewController] ดู]

<UILayoutContainerView: 0xf7296f0; เฟรม = (0 0; 320 480); ปรับขนาดอัตโนมัติ = W + H; เลเยอร์ = <CALayer: 0xf729b80 >>

ไม่แน่ใจว่าแอปของคุณทำงานอย่างไร แต่หากคุณไม่ได้ใช้ตัวควบคุมการนำทางบางประเภทคุณอาจมี UIView ภายใต้มุมมองหลักของคุณโดยมีความสูง / ความกว้างสูงสุดของพาเรนต์และขยาย / ย่อขนาดพร้อมพาเรนต์ จากนั้นคุณสามารถทำได้: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]. มันดูค่อนข้างรุนแรงในบรรทัดเดียว แต่คุณเข้าใจแล้ว

อย่างไรก็ตาม ... มันจะดีกว่าถ้าทำ 3 ขั้นตอนข้างต้นภายใต้บทสรุป เริ่มยุ่งกับ UIWindows แล้วคุณจะพบสิ่งแปลก ๆ เช่นการแสดง UIAlertView จะเปลี่ยนคีย์วินโดว์ของ UIApplication ให้ชี้ไปที่ UIWindow ใหม่ที่ UIAlertView สร้างขึ้น ใครจะรู้? ฉันทำหลังจากพบข้อผิดพลาดที่อาศัย keyWindow และพบว่ามันเปลี่ยนไปอย่างนั้น!


5
ดูเหมือนจะเป็นงานพื้นฐานที่ฉันมีปัญหาในการเชื่อว่าฉันต้องแฮ็กรหัสของตัวเองเพื่อตรวจสอบอะไรแบบนี้
MusiGenesis

2
ฉันจะลองวิธีอื่นและโพสต์ใหม่ถ้ามันได้ผล ไซต์นี้ก้าวร้าวมากหากคุณไม่ตอบอย่างรวดเร็วคุณอาจไม่ตอบเลยเช่นกัน ฮ่าฮ่า ... : ฉันหวังว่าคำตอบของฉันจะเป็นประโยชน์อย่างน้อย อีกครั้งฉันจะลองอย่างอื่นด่วน
แซม

1
เยี่ยมมาก! (BTW หนึ่งมีความสนใจของใครคนหนึ่ง) :-)
Vamos

1
หากคุณใช้applicationFrameแทนbounds(บนหน้าจอ UIS) คุณไม่จำเป็นต้องลบความสูงของแถบสถานะ
aopsfan

2
stackoverflow.com/questions/24150359/… mainScreen().bounds.sizeได้กลายเป็นการวางแนวโดยขึ้นอยู่กับ iOS 8 เป็นต้นไป
Gerald

39

นี่คือรหัสวิธีการแก้ปัญหาของฉันวิธีนี้สามารถเพิ่มลงในหมวดหมู่ของคลาส NSObject หรือคุณสามารถกำหนดคลาส UIViewController ที่กำหนดเองอันดับต้น ๆ และปล่อยให้ UIViewControllers อื่น ๆ ทั้งหมดของคุณสืบทอดมัน

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

หมายเหตุหลังจาก IOS8 ตามที่Apple Document ของคุณสมบัติขอบเขตของ UIScreenกล่าวว่า:

อภิปรายผล

รูปสี่เหลี่ยมนี้ระบุไว้ในพื้นที่พิกัดปัจจุบันซึ่งคำนึงถึงการหมุนอินเทอร์เฟซที่มีผลสำหรับอุปกรณ์ ดังนั้นค่าของคุณสมบัตินี้อาจเปลี่ยนแปลงเมื่ออุปกรณ์หมุนระหว่างแนวตั้งและแนวนอน

ดังนั้นเพื่อพิจารณาความเข้ากันได้เราควรตรวจหาเวอร์ชัน IOS และทำการเปลี่ยนแปลงดังต่อไปนี้:

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

ค่อนข้างเหมือนกับคำตอบของฉันสิ่งเดียวที่พลาดคือถ้ามันอยู่ในแนวตั้งกลับหัว สิ่งนี้จะสำคัญก็ต่อเมื่อคุณสนับสนุนการวางแนวนั้น
Robert Wagstaff

2
@Monjer คุณไม่ควรตั้งชื่อเมธอดที่ไม่ดำเนินการตามคำขอ GET โดยนำหน้าฉันด้วยคำว่า get currentScreenBoundsDependOnOrientation เป็นชื่อที่ดีกว่าสำหรับวิธีการ
bogen

1
@ Hakonbogen.yes อาจเป็นคุณพูดถูกเพราะการประกาศ "peroperty" จะสร้างวิธี setter / getter โดยอัตโนมัติและอาจทำให้เกิดความขัดแย้งในการตั้งชื่อและขัดกับหลักการตั้งชื่อของ objc ขอบคุณสำหรับคำแนะนำของคุณ
monjer

เป็นเรื่องดีที่ในที่สุด Apple ก็ยอมรับโดยปริยายว่ารหัสการหมุนของพวกเขาเป็นระเบียบโดยสิ้นเชิงและเพิ่งเริ่มบอกเราว่าขนาดเหี้ยในแนวปัจจุบันเป็นอย่างไร น่าเสียดายที่ใช้เวลาจนถึงเวอร์ชัน 8 เพื่อไปที่นั่น
MusiGenesis

31

นี่คือมาโครที่มีประโยชน์:

#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

ใน iOS 8+ คุณควรใช้viewWillTransitionToSize:withTransitionCoordinatorวิธีการ:

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

สิ่งนี้จะแทนที่วิธีการสร้างภาพเคลื่อนไหวที่เลิกใช้แล้วซึ่งไม่ได้ให้ข้อมูลเกี่ยวกับขนาด:

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

นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ทันสมัยและเป็นปัจจุบัน
SarpErdag

ใช้คำตอบนี้สำหรับ ios 8 ขึ้นไป
iPhoneDeveloper

10

ขณะนี้ขอบเขตของหน้าจอ iOS 8 จะถูกส่งกลับอย่างถูกต้องสำหรับการวางแนวปัจจุบัน ซึ่งหมายความว่า iPad ในแนวนอน [UIScreen mainScreen] ขากลับจะส่งคืน 768 บน iOS <= 7 และ 1024 บน iOS 8

ต่อไปนี้ส่งคืนความสูงและความกว้างที่ถูกต้องในทุกเวอร์ชันที่ออก

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

หากคุณต้องการขนาดขึ้นอยู่กับการวางแนวและคุณมีมุมมองคุณสามารถใช้:

view.bounds.size

สุดยอด! KISS solution = Keep It Simple and Stupid
bsorrentino

3
KISS ไม่ได้หมายความว่า "Keep it Simple and Stupid" - LOL! หมายความว่า "ให้มันง่ายโง่!" :-)
Erik van der Neut

นอกจากนี้คำตอบนี้ใช้ได้ผลก็ต่อเมื่อมุมมองของคุณทราบว่าเป็นแบบเต็มหน้าจอเท่านั้น แต่ถ้าเป็นเช่นนั้นคุณอาจไม่มีปัญหาเดิมที่ OP โพสต์ไว้
Erik van der Neut

5

ผมเขียนประเภทUIScreenที่ผลงานในทุกรุ่น iOS
[[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
นี่เป็นคำตอบที่สะอาดที่สุดสำหรับฉัน โหวตขึ้น
Erik van der Neut

5

นี่คือวิธีที่รวดเร็วในการรับขนาดหน้าจอที่ขึ้นกับการวางแนว:

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
}

สิ่งเหล่านี้รวมอยู่ในฟังก์ชันมาตรฐานในโครงการของฉัน:

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

อย่างไรก็ตามบน 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;
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.