Detecting iPhone 6/6+ screen sizes in point values

2020-01-26 12:59发布

Given the newly announced iPhone 6 screen sizes:

iPhone 6: 1334h * 750w @2x (in points: 667h * 375w)
iPhone 6+: 1920 * 1080 @3x (in points: 640h * 360w)

I was wondering if there is code that allows me to detect which screen size the user's device is, so that I could adjust and size UIImages and other materials accordingly with the user's device.

So far, I have been using the following:

- (NSString *) platform{
    size_t size;
    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    char *machine = malloc(size);
    sysctlbyname("hw.machine", machine, &size, NULL, 0);
    NSString *platform = [NSString stringWithUTF8String:machine];
    free(machine);
    return platform;
}

- (NSString *) platformString{
    NSString *platform = [self platform];
    if ([platform isEqualToString:@"iPhone1,1"])    return @"iPhone 1G";
    if ([platform isEqualToString:@"iPhone1,2"])    return @"iPhone 3G";
    if ([platform isEqualToString:@"iPhone2,1"])    return @"iPhone 3GS";
    if ([platform isEqualToString:@"iPhone3,1"])    return @"iPhone 4";
    if ([platform isEqualToString:@"iPhone3,3"])    return @"Verizon iPhone 4";
    if ([platform isEqualToString:@"iPhone4,1"])    return @"iPhone 4S";
    if ([platform isEqualToString:@"iPhone5,1"])    return @"iPhone 5 (GSM)";
    if ([platform isEqualToString:@"iPhone5,2"])    return @"iPhone 5 (GSM+CDMA)";
    if ([platform isEqualToString:@"iPhone5,3"])    return @"iPhone 5c (GSM)";
    if ([platform isEqualToString:@"iPhone5,4"])    return @"iPhone 5c (GSM+CDMA)";
    if ([platform isEqualToString:@"iPhone6,1"])    return @"iPhone 5s (GSM)";
    if ([platform isEqualToString:@"iPhone6,2"])    return @"iPhone 5s (GSM+CDMA)";
    if ([platform isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";
    if ([platform isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";
    if ([platform isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";
    if ([platform isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";
    if ([platform isEqualToString:@"iPod5,1"])      return @"iPod Touch 5G";
    if ([platform isEqualToString:@"iPad1,1"])      return @"iPad";
    if ([platform isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";
    if ([platform isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";
    if ([platform isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
    if ([platform isEqualToString:@"iPad2,4"])      return @"iPad 2 (WiFi)";
    if ([platform isEqualToString:@"iPad2,5"])      return @"iPad Mini (WiFi)";
    if ([platform isEqualToString:@"iPad2,6"])      return @"iPad Mini (GSM)";
    if ([platform isEqualToString:@"iPad2,7"])      return @"iPad Mini (GSM+CDMA)";
    if ([platform isEqualToString:@"iPad3,1"])      return @"iPad 3 (WiFi)";
    if ([platform isEqualToString:@"iPad3,2"])      return @"iPad 3 (GSM+CDMA)";
    if ([platform isEqualToString:@"iPad3,3"])      return @"iPad 3 (GSM)";
    if ([platform isEqualToString:@"iPad3,4"])      return @"iPad 4 (WiFi)";
    if ([platform isEqualToString:@"iPad3,5"])      return @"iPad 4 (GSM)";
    if ([platform isEqualToString:@"iPad3,6"])      return @"iPad 4 (GSM+CDMA)";
    if ([platform isEqualToString:@"iPad4,1"])      return @"iPad Air (WiFi)";
    if ([platform isEqualToString:@"iPad4,2"])      return @"iPad Air (Cellular)";
    if ([platform isEqualToString:@"iPad4,4"])      return @"iPad mini 2G (WiFi)";
    if ([platform isEqualToString:@"iPad4,5"])      return @"iPad mini 2G (Cellular)";
    if ([platform isEqualToString:@"i386"])         return @"Simulator";
    if ([platform isEqualToString:@"x86_64"])       return @"Simulator";
    return platform;
}

As such, should I assume iPhone7,1 and iPhone7,2 are the iPhone 6 while iPhone7,3 and iPhone7.4 are the pluses? If anyone has more concrete way to tell it'd be great, thanks.!

标签: ios iphone ios8
16条回答
三岁会撩人
2楼-- · 2020-01-26 13:06

One major thing that the above answers are leaving out is the fact that in iOS7 and below, when you check [[UIScreen mainScreen] bounds] for the screen bounds, it always lists the width and height as the same no matter what orientation the phone is in. So if it's an iPhone5 in landscape mode, it will still list the width as 320 and height as 568. In iOS8, this changed, now if that same iPhone5 is in landscape, it will list the width as 568 and the height as 320. Below are methods which account for this:

+ (BOOL) deviceHasFourInchScreen
{
    return [DeviceType deviceHasScreenWithIdiom:UIUserInterfaceIdiomPhone scale:2.0 height:568.0];
}

+ (BOOL) deviceHasFourPointSevenInchScreen
{
    return [DeviceType deviceHasScreenWithIdiom:UIUserInterfaceIdiomPhone scale:2.0 height:667.0];
}

+ (BOOL) deviceHasFivePointFiveInchScreen
{
    return [DeviceType deviceHasScreenWithIdiom:UIUserInterfaceIdiomPhone scale:3.0 height:736.0];
}

+ (BOOL) deviceHasScreenWithIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom scale:(CGFloat)scale height:(CGFloat)height
{
    CGRect mainScreenBounds = [[UIScreen mainScreen] bounds];
    CGFloat mainScreenHeight;

    if ([OperatingSystemVersion operatingSystemVersionLessThan:@"8.0"])
    {
        mainScreenHeight = mainScreenBounds.size.height;
    }
    else
    {
        mainScreenHeight = (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) ? mainScreenBounds.size.width : mainScreenBounds.size.height;
    }

    if ([[UIDevice currentDevice] userInterfaceIdiom] == userInterfaceIdiom && [[UIScreen mainScreen] scale] == scale && mainScreenHeight == height)
    {
        return YES;
    }
    else
    {
        return NO;
    }
}

Also here are the accompanying OperatingSystem class methods:

+ (NSString *) currentOperatingSystemVersion
{
    return [[UIDevice currentDevice] systemVersion];
}
+ (BOOL) operatingSystemVersionLessThanOrEqualTo:(NSString *) operatingSystemVersionToCompare
{
    return ([[self currentOperatingSystemVersion] compare: operatingSystemVersionToCompare options:NSNumericSearch] != NSOrderedDescending);    
}
查看更多
一纸荒年 Trace。
3楼-- · 2020-01-26 13:08

On the physical device, iPhone 6 Plus's main screen's bounds is 2208x1242 and nativeBounds is 1920x1080. There is hardware scaling involved to resize to the physical display.

On the simulator, the iPhone 6 Plus's main screen's bounds and nativeBounds are both 2208x1242.

In other words... Videos, OpenGL, and other things based on CALayers that deal with pixels will deal with the real 1920x1080 framebuffer on device (or 2208x1242 on sim). Things dealing with points in UIKit will be deal with the 2208x1242 (x3) bounds and get scaled as appropriate on device.

The simulator does not have access to the same hardware that is doing the scaling on device and there's no really much of a benefit to simulating it in software as they'd produce different results than the hardware. Thus it makes sense to set the nativeBounds of a simulated device's main screen to the bounds of the physical device's main screen.

iOS 8 added API to UIScreen (nativeScale and nativeBounds) to let a developer determine the resolution of the CADisplay corresponding to the UIScreen.

查看更多
唯我独甜
4楼-- · 2020-01-26 13:09

this is guaranteed to compile in xcode 5 (xocde 6 at this point is still flaky, and you can't submit an ipa to itunes connect for app store approval using beta software, which xcode 6 is right now)

the thing is xcode 5 won't recognize the nativeScale selector.. this is how you can do it in run time:

+ (BOOL)isIphone6Plus
{
    SEL selector = NSSelectorFromString(@"nativeScale");
    if ([[UIScreen mainScreen] respondsToSelector:selector]) {
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
                                        [[[UIScreen mainScreen] class] instanceMethodSignatureForSelector:selector]];
            [invocation setSelector:selector];
            [invocation setTarget:[UIScreen mainScreen]];
            [invocation invoke];
            float returnValue;
            [invocation getReturnValue:&returnValue];
            NSLog(@"::: this is native scale %f", returnValue);
            return (returnValue == 3.0f);
    } else {
        // iphone 6 plus come prepackaged with iOS8.. 
        // so if the phone doesn't know what nativeScale means
        // it's not an iphone6plus phone
        return NO;
    }
}
查看更多
beautiful°
5楼-- · 2020-01-26 13:11

All three devices have (pretty much) the same number of points per inch. So your images will automatically be the same physical size.

Use [[UIScreen mainScreen] bounds] to get the total number of points on the screen. Divide by 163 to get the approximate size in inches if you really want it.

Notice that the 6+ does not return 1080p because it doesn't render to a 1080p buffer. It renders such that output is approximately 160 points per inch, using @3x assets.

No need to second guess.

E.g. if you write this code:

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 163, 163)];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];

You'll get a view that is pretty much the same physical size — one inch square — on all iOS devices.

Apple has already done the hard work, so you don't have to.

查看更多
Explosion°爆炸
6楼-- · 2020-01-26 13:15

The first screen will be the device screen, Note that a launch images for the new phones have to be added before, otherwise the app is running in Zoomed Mode for older apps : Here is the code I used to check this out. Note: This only works with version iOS 8 and higher:

UIScreen *mainScreen = [UIScreen mainScreen];
NSLog(@"Screen bounds: %@, Screen resolution: %@, scale: %f, nativeScale: %f",
          NSStringFromCGRect(mainScreen.bounds), mainScreen.coordinateSpace, mainScreen.scale, mainScreen.nativeScale);

Code for detecting iPhone 6 Plus:

#define IS_PAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_PHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)

-(BOOL)iPhone6PlusDevice{
    if (!IS_PHONE) return NO;
    if ([UIScreen mainScreen].scale > 2.9) return YES;   // Scale is only 3 when not in scaled mode for iPhone 6 Plus
    return NO;
}

or

-(BOOL) iPhone6PlusUnZoomed{
    if ([self iPhone6PlusDevice]){
        if ([UIScreen mainScreen].bounds.size.height > 720.0) return YES;  // Height is 736, but 667 when zoomed.
    }
    return NO;
}

Note: If you are checking for iPhone 6 Plus, to adjust the user interface then don´t rely on .nativeScale, because the simulator and actual device give different results. Due to the comment below. Scale is a CGFloat and thus, code should not check equality, because some floats values may never be equal.


After adding Launch Screen you can utilise the new iPhone sizes, otherwise your app will still look scaled.

Updated for the new iPhones 11, 11 Pro and 11 Pro Max

Size for iPhone 11 Pro Max with @3x scaling, coordinate space: 414 x 896 points and 1242 x 2688 pixels, 458 ppi, device physical size is 3.06 x 6.22 in or 77.8 x 158.0 mm. 6.5" Super Retina XDR display.

Size for iPhone 11 Pro with @3x scaling, coordinate space: 375 x 812 points and 1125 x 2436 pixels, 458 ppi, device physical size is 2.81 x 5.67 in or 71.4 x 144.0 mm. 5.8" Super Retina XDR display.

Size for iPhone 11 with @2x scaling, coordinate space: 414 x 896 points and 828 x 1792 pixels, 326 ppi, device physical size is 2.98 x 5.94 in or 75.7 x 150.9 mm. 6.1" Liquid Retina HD display.

Size for iPhone X

查看更多
ら.Afraid
7楼-- · 2020-01-26 13:15

Check the updated list on wiki , there I got 7,2 for iPhone 6 and 7,1 for iPhone 6 plus.

查看更多
登录 后发表回答