Có phải [UIScreen mainScreen] .bound.size trở nên phụ thuộc vào định hướng trong iOS8 không?


184

Tôi đã chạy mã sau trong cả iOS 7 và iOS 8:

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

Sau đây là kết quả từ iOS 8:

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

So sánh với kết quả trong iOS 7:

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

Có tài liệu nào chỉ định thay đổi này không? Hay đó là một lỗi tạm thời trong API iOS 8?


13
Chà, đầu ra iOS8 có vẻ hợp lý hơn nhiều
Levi

Câu trả lời:


173

Có, nó phụ thuộc vào định hướng trong iOS8, không phải là lỗi. Bạn có thể xem lại phiên 214 từ WWDC 2014 để biết thêm thông tin: "Xem tiến bộ điều khiển trong iOS 8"

Trích dẫn từ bài thuyết trình:

UIScreen hiện được định hướng giao diện:

  • [Giới hạn màn hình] giờ hướng giao diện
  • [Khung ứng dụng UIScreen] hiện được định hướng giao diện
  • Thông báo khung thanh trạng thái được định hướng giao diện
  • Thông báo khung bàn phím được định hướng giao diện

7
Trong bài giảng WWDC đã đề cập ở trên, phần định hướng giao diện bắt đầu từ 51:50.
cnotethegr8

2
Tôi đã dành hầu hết ngày hôm nay để cố gắng làm việc xung quanh sự tiến bộ này. Rõ ràng điều đó không phải lúc nào cũng xảy ra, vì vậy nếu bạn là nhà phát triển SDK cần hoạt động trong các ứng dụng khác, thì công cụ này thậm chí còn phức tạp hơn.
Glenn Maynard

1
@aroth bạn không thể đổi mới mà không cần phanh một số thói quen cũ.
Boris Y.

23
@borisy - Tôi tôn trọng không đồng ý. Trong hầu hết các trường hợp, nó có thể đổi mới trong khi vẫn duy trì khả năng tương thích ngược. Theo tôi, sự thay đổi phá vỡ sự lười biếng hơn bất cứ điều gì khác. Họ muốn mọi người khác làm việc.
vào

1
Câu trả lời này sẽ hữu ích hơn nữa nếu nó được giải thích ý nghĩa thực sự của giao diện . Tôi có thể sai, nhưng tôi nghĩ rằng sự phụ thuộc định hướng chỉ liên quan đến việc xem các bộ điều khiển. Nếu bạn lấy bất kỳ lớp nào khác và tính các giới hạn, chúng vẫn theo kiểu cũ, luôn luôn là chân dung.
Maxi Mus

59

Có, nó phụ thuộc vào định hướng trong iOS8.

Tôi đã viết một phương pháp Util để giải quyết vấn đề này cho các ứng dụng cần hỗ trợ các phiên bản cũ hơn của HĐH.

+ (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
Tôi đã chỉnh sửa mã, vui lòng kiểm tra, điều kiện của bạn để kiểm tra phiên bản HĐH là sai
Jageen

@Jageen Xin làm rõ, kiểm tra phiên bản làm việc cho tôi. Vấn đề là gì?
cbartel

Điều tôi hiểu là, chúng ta cần thay đổi chiều cao và chiều rộng nếu HĐH là iOS8 và định hướng là Cảnh ,, tôi có đúng không?
Jageen

@Jageen Phủ định, trong iOS 8 phương thức phụ thuộc vào định hướng. Logic của bạn được chuyển đổi. Chỉnh sửa của bạn đã bị từ chối chính xác.
cbartel

@cbartel có cách nào để phân loại điều này thành UIScreen để cuộc gọi ban đầu của chúng tôi đến [UIScreen mainScreen] .bound.size sẽ hoạt động cho cả iOS 7 và iOS 8?
kevinl

34

Đúng vậy, thực sự, kích thước màn hình hiện phụ thuộc vào định hướng trong iOS 8. Tuy nhiên, đôi khi, mong muốn có được kích thước cố định với hướng dọc. Đây là cách tôi làm điều đó.

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

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

2
Tôi thấy rằng điều này khắc phục sự cố với các ứng dụng iPhone thông thường, nhưng không phải với các ứng dụng iPhone chạy trên iPad.
ThomasW

32

Vâng, bây giờ nó phụ thuộc vào định hướng.

Tôi thích phương pháp dưới đây để có được kích thước màn hình theo cách độc lập với hướng đối với một số câu trả lời ở trên, vì nó đơn giản hơn và vì nó không phụ thuộc vào bất kỳ mã định hướng nào (trạng thái có thể phụ thuộc vào thời gian mà chúng được gọi) hoặc kiểm tra phiên bản. Bạn có thể muốn hành vi iOS 8 mới, nhưng điều này sẽ hoạt động nếu bạn cần nó ổn định trên tất cả các phiên bản iOS.

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

Có lẽ sẽ không hoạt động trên một cái gì đó giống như Apple TV, nơi mà nó (hầu như) luôn rộng hơn chiều cao.
cbh2000

11

Liên quan đến câu hỏi này vì nó đã giải quyết vấn đề của tôi, ở đây có hai định nghĩa tôi sử dụng để tính toán chiều rộng và chiều cao màn hình:

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

Nếu bạn đang hỗ trợ cả iOS 7 và iOS 8, đây là giải pháp tốt nhất cho vấn đề này.


@Namit Gupta, chỉnh sửa của bạn là sai. Nếu phiên bản IOS từ 8 trở lên, chúng ta có thể sử dụng kích thước UIScreen vì chúng phụ thuộc vào hướng. Trước iOS 8, bạn phải kiểm tra hướng thanh trạng thái. Chỉnh sửa của bạn hiện đang nói rằng tất cả các phiên bản iOS không thấp hơn 8 thì nên kiểm tra trạng thái sai, điều này là sai.
Antoine

9

Bạn có thể sử dụng nativeBounds(không phụ thuộc vào định hướng)

bản địa

Hình chữ nhật giới hạn của màn hình vật lý, được đo bằng pixel. (chỉ đọc)

Tuyên bố SWift

  var nativeBounds: CGRect { get }

Hình chữ nhật này dựa trên thiết bị theo hướng dọc. Giá trị này không thay đổi khi thiết bị quay.

Phát hiện chiều cao của thiết bị:

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

}

Phát hiện chiều rộng của thiết bị:

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

}

3
Xin lưu ý rằng phương thức này trả về pixel, trong khi hầu hết các phương thức khác xử lý điểm. Những điều rất khác nhau.
jcsahnwaldt phục hồi lại

1
Trong trường hợp của tôi chính xác là những gì tôi cần :) (OpenGL hoặc các Chế độ xem khác không dựa trên UIView nhưng tôi cần biết chính xác kích thước pixel)
Bersaelor

3
Cảnh báo: trên iphone 6+, điều này đã trả về 1080 x 1920, đây có thể không phải là điều bạn muốn
Chanon

8

Đây không phải là một lỗi trong SDK iOS 8. Họ đã định hướng giao diện giới hạn phụ thuộc. Theo câu hỏi của bạn về một số tài liệu tham khảo hoặc tài liệu cho thực tế đó, tôi sẽ khuyên bạn nên xem View Controller Advancements in iOS 8đó là phiên 214 từ WWDC 2014 . Phần thú vị nhất (theo nghi ngờ của bạn) là Screen Coordinatesbắt đầu từ 50:45.


5

Có, nó phụ thuộc vào định hướng trong iOS8.

Đây là cách bạn có thể có cách đọc đồng thời các giới hạn theo kiểu iOS 8 trên các phiên bản SDK và OS.

#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
Kiểm tra phiên bản SDK cũng là một mẹo hay trong trường hợp đồng nghiệp đang xây dựng ứng dụng của bạn với các phiên bản SDK khác nhau (mặc dù điều đó không nên xảy ra!).
Craig McMahon

4

Giải pháp của tôi là sự kết hợp giữa MaxK's và hfossli. Tôi đã thực hiện phương pháp này trên Danh mục UIScreen và nó không có kiểm tra phiên bản (đó là một thực tiễn xấu):

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

Tôi cần một chức năng trợ giúp nhanh, giữ hành vi tương tự như iOS7 trong iOS8 - điều này cho phép tôi trao đổi [[UIScreen mainScreen] bounds]các cuộc gọi của mình và không chạm vào mã khác ...

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

Khó chịu, nhưng hoàn thành công việc cho đến khi có thời gian để sửa chữa mọi thứ một cách chính xác :-)
DuneCat

3

Phương pháp dưới đây có thể được sử dụng để tìm giới hạn màn hình cho một hướng nhất định, độc lập với phiên bản iOS. Phương pháp này sẽ trả về giới hạn dựa trên kích thước màn hình của thiết bị và sẽ cho cùng một giá trị CGRect độc lập với phiên bản iOS.

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

Đó là những gì tôi đã sử dụng để tính toán chính xác:

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

Chỉ cần thêm phiên bản nhanh chóng của một chức năng cbartel tuyệt vời đã trả lời ở trên.

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

Vấn đề của tôi liên quan đến khung UIWindows đang bị trừ. Vì vậy, đã tạo mã như dưới đây trong MyViewControll - (NSUInteger) được hỗ trợInterfaceOrientations Phương thức

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

Và nó làm việc cho tôi thử nó.


1

iOS 8 trở lên

Một giải pháp cho những ai muốn tìm hiểu kích thước màn hình theo điểm (màn hình 3,5 inch có 320 × 480 điểm, màn hình 4.0 inch có 320 × 568 điểm, v.v.) sẽ là

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

Một điều mà tôi lưu ý là, thứ tự các hướng giao diện được hỗ trợ trong Info.plist có vấn đề. Tôi đã gặp vấn đề với câu hỏi này với ứng dụng của mình (đó là định hướng trong mã), nhưng tôi không chỉ định bất kỳ nơi nào định hướng mặc định là Portrait.

Tôi nghĩ rằng định hướng mặc định Portrait trong mọi trường hợp.

Sắp xếp lại itens trong Info.plist, đặt Portrait trước, khôi phục hành vi dự kiến.


0

Điều này sẽ cung cấp cho thiết bị chính xác trong iOS7iOS8 ,

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

// Bạn cũng có thể thêm nhiều thiết bị hơn (ieiPad).


Câu hỏi không phải là về nhận dạng thiết bị dựa trên độ phân giải màn hình. Ngoài ra, Apple khuyến nghị tạo UI thích ứng dựa trên các lớp kích thước không dựa trên phát hiện thiết bị / màn hình
Julian Król

0

Đã sử dụng giải pháp của mnemia đã được sửa đổi một chút, đó là giải pháp không có phiên bản iOS, sử dụng min / max trên giới hạn màn hình chính.
Tôi cần một CGRectcái như vậy CGRecttừ giới hạn màn hình chính và thay đổi size.width=min(w,h), size.height=max(w,h). Sau đó, tôi gọi đó là hệ điều hành độc lập get CGRectchức năng ở hai nơi trong mã của tôi, nơi tôi nhận được kích thước màn hình cho OpenGL, chạm vv Trước khi sửa chữa tôi đã có 2 vấn đề - trên IOS 8.x trong bối cảnh vị trí chế độ hiển thị của OpenGLquan điểm không chính xác: 1 / 4 toàn màn hình ở phần dưới cùng bên trái. Và lần chạm thứ hai trả về giá trị không hợp lệ. Cả hai vấn đề đã được khắc phục như được giải thích. Cảm ơn!

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.