Saturday, November 10, 2012

Interlude 13 - Pixels vs Points in iOS

In the previous tutorial we had to deal with a number of different resolutions in order to be able to develop a universal app. The following is a quick refresher on how to do this.

From iOS 4, dimensions are measured in “points” instead of pixels. All coordinate values and distances are specified using points, which are floating-point values. The measurable size of a point varies from device to device and is largely irrelevant. The main thing to understand about points is that they provide a fixed frame of reference for drawing.

The iPhone screen is 320 x 480 points on both iPhone 4 and older models. The iPhone 4 has a screen resolution of 640 x 960 pixels (i.e. a scale factor of 2.0) while older models have a resolution of 320 x 480 pixels (i.e. a scale factor of 1.0).

The iPad screen is 768 x 1024 points. This scales to the following pixel resolutions:
  • iPad 1 - 768 x 1024 pixels (i.e. a scale factor of 1.0)
  • iPad 2 - 768 x 1024 pixels
  • iPad 3 - 1536 x 2048 pixels (i.e. a scale factor of 2.0)
  • iPad 4 - 1536 x 2048 pixels
  • iPad Mini - 768 x 1024 pixels
Retina is a marketing term developed by Apple. It refers to devices and monitors that have such a high pixel density (normally greater than 300 pixels per inch) that most people can't discern individual pixels at a normal viewing distance. We wont use this term in our explanation because it is inexact and differs by device (e.g. iPhone 4/5 is 326 ppi, iPad mini is 163 ppi, iPad 1 and 2 is 132 ppi, iPad 3 and 4 is 264 ppi - note that the iPad 3 and 4 don't strictly meet the Retina "standard"). 

Querying the scale factor is the best way to determine the relationship between pixels and points on the current device. In iOS 4 and later, UIScreen has a property called scale which is a floating point number that defines the pixel/point relationship. In Objective C you can get this number using:

[[UIScreen mainScreen] scale]

On an iPhone 4 and 5 a point is a four pixel square, so if you draw a one-point line, it shows up as two pixels wide. The theory is that you specify your measurements in points for all devices, and iOS automatically draws everything to the right proportion on the screen. The result is that if you draw the same content on two similar devices, with only one of them having a high-resolution screen, the content appears to be about the same size on both devices. This is why you go to the trouble of creating your @2x images.

The iPhone 5 has a physical resolution of 1136 x 640 pixels which equates to 568 x 320 points. Your WIDTH and HEIGHT constants return points not pixels. So the best test for an iPhone 5 within Codea is to look for the 568 dimension.

Within your Objective C code you can determine the device using something like the following:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        NSLog(@"iPad device detected.");
else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
        CGSize result = [[UIScreen mainScreen] bounds].size;
        if (result.height == 480)
            NSLog(@"iPhone/iPod Touch detected (< v5).");
        if (result.height == 568)
            NSLog(@"iPhone/iPod Touch detected (> v5).");