Pixel density in a troubled world

Whereas in the past user interface design would largely be concerned with screen size or display resolution, now the question of how many pixels make up one inch becomes relevant as well. This measure is called pixel density, and is expressed in dpi or ppi units. Nowhere is pixel density as broadly distributed as in the mobile world. A low-end android mobile may have a 180 dpi screen, while a high-end one, like the retina display, will boast up to a 326 dpi screen.

Pixel density affects the physical size of display artifacts. It boils down to this: one and the same button that is, say, 50 pixels in width, will appear larger on a lower density screen and narrower on a higher density screen. Since the user eventually uses his thumb to press on the button, it is critical that it be physically large enough so as not to be missed, but not too large because screen estate is precious and must be shared with the rest of the UI elements.

To help write clean and accurate UI interfaces, mobile development frameworks should, as they often do, abstract device-dependent pixel size with some sort of density-independent measure unit. The Android platform has devised such a density-independent pixel; it is aligned on a baseline density assumed by the platform (160dpi), where scaling is then internally handled based on the actual density of the screen in use. But when you are developing an AS3 project in Adobe Air, you have to come up with a solution of your own.

Christian Cantrell, a developer from Adobe, has attempted something quite ambitious with his iReverse project. It’s a board game written in pure AS3, one single codebase that can adapt to all the environments supported by Flash and Air (Ipad, Iphone, Android, Desktop and browser). To achieve this goal, a variety of techniques are used (which are discussed at length in “Writing multiscreen AIR apps” and “Authoring mobile Flash content for multiple screen sizes”), but we are going to focus on our topic of discussion, pixel density. The density-independent measure, in Christian’s project, is physical reality. Think not in pixels, but in inches.

private function inchesToPixels(inches:Number):uint
        return Math.round(Capabilities.screenDPI * inches);

Alternatively, for developers used to the european metrics systems, the idea is to think directly in millimeters.

private function mmToPixels(mm:Number):uint
        return Math.round(Capabilities.screenDPI * (mm / 25.4));

Buttons on a UI for mobile need to be at least 7mm wide if they should be effective (and not a hit & miss affair), you would define them in you code like this:

myButton.width = mmToPixels(7);

The reasoning is flawless, the problem lies with the reliability of Capabilities.screenDPI. Needless to say, this is a factor beyond Christian Cantrell’s control, but it appears that Capabilities.screenDPI reports a set of hard-coded values, which renders it less useful, and to a certain extent ruins Christian’s solution. I was surprised by this myself, I thought such an essential API – querying the host for info about its screen characteristics – would be accurate, but alas, it is not the case (see note).

This is the reason why Christian Cantrell overrides this value with a better approximation. For the Ipad, for example, there is no ambiguity, the correct value is 132 dpi (as of now there is only one Ipad model). Whether or not the Flash runtime can report this, Christian can always pass an overridden dpi value to the main application thanks to the wrappers that he uses for each platform. But what is a better approximation for the android platform where so many devices display so many different characteristics? There is no such thing, and an average value will make it only worse, resulting in UI soup. Of course, you can always compile different binaries optimized for different screens, but then you’re asking for trouble publishing-wise, and besides, can anyone see the irony of having a unified codebase but a fragmented binary distribution? This can be felt acutely on the Android Market, where the customary rule is that one .apk package serves all devices.

Eventually, the Flex mobile framework will solve the pixel density conundrum with a components approach. A well-written component set promises adaptive layout logic and self-contained resizing mechanisms, effectively abstracting pixel density considerations from the developer. But if you had hopes to distribute a pure AS3 application on the Android Market here and now, you’re in for a dilemma and no satisfying solution.

Note: On my desktop, a call to Capabilities.screenDPI returns 72 dpi instead of the real value of 102 dpi, on my android phone, the call returns 254 instead of the actual 267 dpi value.

Link: List of displays by pixel density

P.S. Follow me on Twitter.

Daniel Szmulewicz 03 January 2011
blog comments powered by Disqus