Android density buckets, or how to work with your designers…

by
Tags: , , , ,
Category: , ,

Android development is very rewarding in a sense that you see results of your work right away. You can also deploy it right to your phone or a tablet and brag about it to your friends.
However, there are pitfalls…

From the beginning everything seems to fall right in place with a very structured environment, great tools (Android Studio and various emulators) that embarrassingly do so much work for you that it feels like cheating. That is of course until you get used to them and start to dig deeper. One of the potentially frustrating aspects of developing for Android is trying to figure out the UI. Let’s take a look at it step by step.

Android allows you to design UI in a combination of two ways: declaratively and imperatively.
You do a declaration of your basic layout in XML files, and then you tweak it or make it dynamic by reaching into it from your Java code. But how do you instruct a phone to layout your design one way and tablet another? Without going into specifics of Android Studio (which pretty much does it for you if you know which menu shortcuts to click) let’s take a look at res folder in the root of your project:
res
|
--layout
|
--layout-large
|

Phones will grab XML layout descriptors from layout folder and tablets will grab them from layout-large. Pretty simple, right? …but what about images for icons, backgrounds, and such?

Screen Design Philosophy in Android

Now let’s take a step back and think about philosophy of Android ecosystem. It’s a (almost) free operating system that welcomes all manufacturers of devices that dare to run it. Devices with small screens and large screens, devices with screens of different resolution, devices with different screen density and orientation.
That means that we, as developers need to worry about the uniformity of the screen design, because the same image, let’s say 48px by 48px will look different on screens with different pixel density. Same holds true for your panels, buttons, layouts and various other elements that you define in XML file for the specific layout.
Screen density is defined in dots per inch (dpi) or pixels per inch, whichever you prefer. Lower-end devices may have 120dpi while higher-end devices have over 640dpi.

Density Independent Pixels

To circumvent this problem Google provided us with a notion of density-independent pixels (dp for short) This way you can be sure that if you’ve defined your button to be 48dp by 48dp it will be the same proportion to the size of the screen on all devices. There’s also a concept of scale-independent pixels (sp for short) that should only be used for fonts. In short, you define your text size in sp, and heights and widths of your components in dp.
That’s fine, but if you’re working with designers, they will give you images and those images have no idea what density-independent pixels are… Their heights and widths are in pixels. So how are you, as a developer supposed to deal with it?
You need to learn the word of the day: “density bucket”… well, two words of the day.

What are Density Buckets?

To deal with different screens Google gives you the following density buckets:
ldpi (low) ~120dpi
mdpi (medium) ~160dpi
hdpi (high) ~240dpi
xhdpi (extra-high) ~320dpi
xxhdpi (extra-extra-high) ~480dpi
xxxhdpi (extra-extra-extra-high) ~640dpi

These density buckets are the actual folders under your res folder. BTW, you should never modify or tamper with the folder structure in res folder as it’s managed by Android.
At this point you should read the following article:
Supporting Multiple Screens -it will give you an insight into the screen sizes, scales and various ratios.

Applying Density Buckets

In short, if you want a 48px by 48px icon appear the same on the screen proportionally to other elements you just place it in mdpi directory, a smaller version of this icon in ldpi directory, a larger version in hdpi, and even larger in xhdpi, and so on…
Google defines mdpi as base so ideally your original sizes go there. The OS will then get the icon from the appropriate folder at run time and place it on the screen.
You calculate the sizes of other versions of this icon by the following this guideline:
Iconography
or by referring to this calculator: Density Calculator

Density Gotchas – what’s the base?

The problem is in definition of the base directory. You see, besides those mentioned density buckets there are others. One of them is: tvdpi. It fits somewhere between mdpi and hdpi and was dedicated for television sets. The point is: when you work with designers you need to be aware of all these details.
While working on a project you’ll probably have a target device – a phone or a tablet that your company distributes to the clients and the designers often will give you base icons designed for that device.
We discovered this by taking a caliper to the screen (it was more romantic than enabling a pointer location in debugging menu of the mobile device) and then compared to the printouts from our designers. We found that our base version of the icons was not mdpi, but tvdpi. It’s important to note that Google doesn’t recommend using tvdpi directory at all, but we were using a fairly common tablet currently on the market that’s simply not supposed to have this pixel density… but it does!
After confirming this find using the debugging option on the device we were able to resolve our issues by providing the calculator mentioned above to our designers and having them enter their base icon sizes as tvdpi and then providing us with icons for the rest of density buckets.

Problem solved.

I hope this article helps you better understand Android development.
-Joe Berger