Làm thế nào để có được chiều cao và chiều rộng của màn hình phụ thuộc vào định hướng?


96

Tôi đang cố gắng lập trình xác định chiều cao và chiều rộng hiện tại của ứng dụng của mình. Tôi sử dụng cái này:

CGRect screenRect = [[UIScreen mainScreen] bounds];

Nhưng điều này mang lại chiều rộng là 320 và chiều cao là 480, bất kể thiết bị ở hướng dọc hay ngang. Làm cách nào để xác định chiều rộng và chiều cao hiện tại (tức là phụ thuộc vào hướng thiết bị) của màn hình chính?

Câu trả lời:


164

Bạn có thể sử dụng một cái gì đó như UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)để xác định hướng và sau đó sử dụng các kích thước cho phù hợp.

TUY NHIÊN, trong quá trình thay đổi hướng như trong UIViewController's

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

Sử dụng hướng được chuyển vào toInterfaceOrientationvì statusBarOrientation của UIApplication sẽ vẫn trỏ đến hướng cũ vì nó vẫn chưa thay đổi (vì bạn đang ở trong một willtrình xử lý sự kiện).

Tóm lược

Có một số bài đăng liên quan đến vấn đề này, nhưng mỗi bài đăng dường như chỉ ra rằng bạn phải:

  1. Nhìn vào [[UIScreen mainScreen] bounds]để có được kích thước,
  2. Kiểm tra định hướng của bạn và
  3. Tính chiều cao của thanh trạng thái (nếu được hiển thị)

Liên kết

Mã làm việc

Tôi thường không đi xa đến mức này, nhưng bạn đã kích thích sự quan tâm của tôi. Đoạn mã sau sẽ thực hiện thủ thuật. Tôi đã viết một Chuyên mục về Ứng dụng UIA. Tôi đã thêm các phương thức lớp để nhận được currentSize hoặc kích thước theo một hướng nhất định, đó là những gì bạn sẽ gọi trong UIViewController's 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

Để sử dụng mã cuộc gọi đơn giản [UIApplication currentSize]. Ngoài ra, tôi đã chạy mã trên, vì vậy tôi biết nó hoạt động và báo cáo lại các phản hồi chính xác theo mọi hướng. Lưu ý rằng tôi nhấn vào thanh trạng thái. Điều thú vị là tôi đã phải trừ MIN của chiều cao và chiều rộng của thanh trạng thái.

Hi vọng điêu nay co ich. : D

Suy nghĩ khác

Bạn có thể bắt đầu lấy các thứ nguyên bằng cách xem thuộc tính của UIWindow rootViewController. Tôi đã xem xét điều này trong quá khứ và nó tương tự báo cáo các kích thước giống nhau trong cả dọc và ngang ngoại trừ nó báo cáo có một biến đổi xoay:

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

<UILayoutContainerView: 0xf7296f0; khung = (0 0; 320 480); biến đổi = [0, -1, 1, 0, 0, 0]; tự động hóa = W + H; lớp = <CALayer: 0xf729b80 >>

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

<UILayoutContainerView: 0xf7296f0; khung = (0 0; 320 480); tự động hóa = W + H; lớp = <CALayer: 0xf729b80 >>

Không chắc ứng dụng của bạn hoạt động như thế nào, nhưng nếu bạn không sử dụng một bộ điều khiển điều hướng nào đó, bạn có thể có UIView dưới chế độ xem chính của mình với chiều cao / chiều rộng tối đa của cha mẹ và lớn lên / thu nhỏ lại với cha mẹ. Sau đó, bạn có thể làm: [[[[[[[UIApplication sharedApplication] keyWindow] rootViewController] view] subviews] objectAtIndex:0] frame]. Điều đó trông khá dữ dội trên một dòng, nhưng bạn có ý tưởng.

Tuy nhiên ... Sẽ tốt hơn nếu bạn thực hiện 3 bước trên dưới phần tóm tắt. Bắt đầu làm rối với UIWindows và bạn sẽ tìm ra những thứ kỳ lạ, chẳng hạn như hiển thị UIAlertView sẽ thay đổi keywindow của UIApplication để trỏ đến UIWindow mới mà UIAlertView đã tạo. Ai biết? Tôi đã làm sau khi tìm thấy một lỗi dựa trên keyWindow và phát hiện ra rằng nó đã thay đổi như vậy!


5
Đây có vẻ như là một nhiệm vụ sơ đẳng đến nỗi tôi khó tin rằng mình phải hack mã của chính mình để xác định một thứ như thế này.
MusiGenesis

2
Tôi sẽ thử một giải pháp khác và đăng lại nếu nó hoạt động. Trang web này rất hung hãn nếu bạn không trả lời nhanh, bạn cũng có thể không trả lời được. haha ...: DI hy vọng câu trả lời của tôi ít nhất là hữu ích. Một lần nữa, tôi sẽ thử một cái gì đó khác thực sự nhanh chóng.
Sam

1
Tuyệt quá! (BTW, một người có mối quan tâm của một người) :-)
Vamos

1
Nếu bạn sử dụng applicationFramethay vì bounds(trên UIScreen), bạn không phải trừ chiều cao thanh trạng thái.
aopsfan

2
stackoverflow.com/questions/24150359/… mainScreen().bounds.size đã trở thành định hướng phụ thuộc từ iOS 8 trở đi
Gerald

39

Đây là mã giải pháp của tôi! Phương thức này có thể thêm vào Categroy của lớp NSObject hoặc bạn có thể xác định một lớp UIViewController tùy chỉnh hàng đầu và cho phép tất cả các UIViewControllers khác của bạn kế thừa nó.

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

Lưu ý , sau IOS8, như Tài liệu của Apple về thuộc tính giới hạn của UIScreen cho biết:

Thảo luận

Hình chữ nhật này được chỉ định trong không gian tọa độ hiện tại, có tính đến mọi phép xoay giao diện có hiệu lực đối với thiết bị. Do đó, giá trị của thuộc tính này có thể thay đổi khi thiết bị xoay giữa các hướng dọc và ngang.

vì vậy để xem xét tính tương thích, chúng tôi nên phát hiện phiên bản IOS và thực hiện thay đổi như sau:

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

Khá giống với câu trả lời của tôi, chỉ có điều nó bỏ sót là nếu nó ở chế độ Portrait lộn ngược. Điều này chỉ quan trọng nếu bạn ủng hộ định hướng đó tho.
Robert Wagstaff

2
@Monjer bạn không nên đặt tên cho các phương thức không thực hiện yêu cầu GET, tiền tố i bằng từ get. currentScreenBoundsDependOnOrientation là một cái tên hay hơn cho phương pháp
bogen

1
@ Hakonbogen.yes có thể bạn đúng, vì khai báo “peroperty” tự động tạo phương thức setter / getter và điều này có thể dẫn đến xung đột đặt tên và đi ngược lại quy ước đặt tên của objc. Cảm ơn lời khuyên của bạn.
monjer

Thật tuyệt khi Apple cuối cùng đã ngầm thừa nhận rằng mã xoay của họ hoàn toàn là một mớ hỗn độn và chỉ bắt đầu cho chúng ta biết các kích thước chết tiệt theo hướng hiện tại. Thật tệ là phải đến phiên bản 8 mới đạt được điều đó.
MusiGenesis

30

Đây là một macro hữu ích:

#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

Trong iOS 8+, bạn nên sử dụng viewWillTransitionToSize:withTransitionCoordinatorphương pháp:

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

Điều này thay thế phương pháp hoạt ảnh không dùng nữa không cung cấp thông tin về kích thước:

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

Đây phải là câu trả lời được chấp nhận. Hiện đại và cập nhật.
SarpErdag

Sử dụng câu trả lời này cho ios 8 trở lên.
iPhoneDeveloper

10

Kể từ iOS 8, giới hạn màn hình hiện được trả về đúng với hướng hiện tại. Điều này có nghĩa là iPad ở hướng ngang [UIScreen mainScreen] .bounds sẽ trả về 768 trên iOS <= 7 và 1024 trên iOS 8.

Phần sau trả về chiều cao và chiều rộng chính xác trên tất cả các phiên bản đã phát hành.

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

nếu bạn muốn kích thước phụ thuộc vào hướng và bạn có chế độ xem, bạn chỉ có thể sử dụng:

view.bounds.size

TUYỆT QUÁ! Giải pháp KISS = Keep It Simple và ngốc
bsorrentino

3
KISS không có nghĩa là "Giữ nó đơn giản và ngu ngốc" - LOL! Nó có nghĩa là "Giữ nó đơn giản, ngu ngốc!" :-)
Erik van der Neut

Ngoài ra, câu trả lời này rõ ràng chỉ hoạt động nếu chế độ xem của bạn được biết chính xác là toàn màn hình. Nhưng, nếu đúng như vậy, thì có lẽ bạn không gặp phải vấn đề ban đầu được OP đăng tải.
Erik van der Neut

5

Tôi đã viết loại cho UIScreenrằng công việc trên tất cả các phiên bản iOS, vì vậy bạn có thể sử dụng nó như thế này:
[[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
Đây có vẻ như là câu trả lời rõ ràng nhất đối với tôi. Đã bình chọn.
Erik van der Neut

5

Đây là một cách Swift để có được kích thước màn hình phụ thuộc vào hướng:

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
}

Chúng được bao gồm như một chức năng tiêu chuẩn trong một dự án của tôi:

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

Tuy nhiên, trên 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;
}

0

use -> setNeedsDisplay () cho dạng xem bạn muốn thay đổi kích thước.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.