Sunday, April 20, 2014

1 comment

Android User Interface

When you first think about creating a user interface for an android application, you will soon read about screen size and density. It is easy to understand, that you should provide different picture files for a high-density tablet and a medium-density handheld device.  The part that is hard to understand is the technical implementation. At least it was for me. 

There are a lot of information about layouts, screen sizes and densities throughout the web. Starting point is most likely the support multiple screens site. While this resource provides a good overview of the subject, it misses the most relevant point: which drawable folders respectively which layout folders to create and where to put which files in. 

As most developers won`t read very much before creating their first sample application, the usual starting point is shown in the picture below. 


This works, if you are working just on one device. You will provide one layout and different pictures. Everything looks good until you run your application on different devices. You will notice that you have to make different layouts for handhelds and tablets, since different space is available in each category. If you do care about user experience and how your application looks like on all devices, you will start thinking about this topic again. So how to provide different layouts?

The answer is simple. Create another layout folder and add a useful screen size qualifier.  The android documentation provides qualifiers as small, normal, large and xlarge. While this isn`t false, it is very outdated. As devices running API level 13 and above takes the major market share these days, you should think in smallest width qualifier. There is a lot of information available how to calculate this smallest width qualifier and what density independent pixels are. Let us shorten this up here. To provide a layout for a 10-inch tablet you have to create a folder layout-sw720dp and put your layout.xml in there. Within this layout, you have 1280dp x 720dp to create your user interface. 

Since 7-inch tablets are very popular, we should provide another layout focusing these devices, too. That means you also create a layout-sw600dp folder and layout file. With your normal layout folder respectively layout-sw320dp folder you have at least three different layouts. Furthermore, it is best practice to provide a different layout for big screen handhelds like 5/6-inch devices. Some resources talks about doing this by a layout-sw480dp folder but this will miss devices like the Galaxy S3. It has 720px in smallest width and uses xhdpi density bucket. As you might know, the density independent pixels representing the mdpi folder. The picture size of the other folders calculate itself in relation to this baseline folder. You might heard about the 3:4:6:8 scaling ratio. If not, read more. That means we will need to create a layout-sw360dp folder and layout. If you want your application to be available for devices running API level 12 and below, you have to duplicate this layouts and create layout-large and layout-xlarge folder. The following picture sums this up.



So we design our layout density independent, no problem, but the pictures we have to provide are physical files, which can`t be density independent. This leads us back to the core questions: into which drawable folder should we put which pictures in? 
 
Let us figure out what this means on something like a splash screen. On a 10-inch device, the mdpi splash screen should be 1280x720 pixel. However, on a 4-inch device, the mdpi splash screen should 480x320 pixel. At this point you realize, the default drawable folder aren`t enough to handle all devices.
 
So what`s the conclusion?
Provide more drawable folder to handle them all!
 
To get this straight, take a look at the following picture. It gives a short overview about what`s going on in the world of android. This overview isn`t complete, most likely contains failures and is definitely outdated that moment you read this.

 
So what`s the conclusion?
Provide more drawable folder to handle them all!  
 
You can see the size qualifier and the resource qualifier as parallel state charts. You just have to combine them. You do this by adding the size qualifier in the name of each drawable folder. For example, you create a folder named drawable-sw720dp-xhdpi to provide high-resolution pictures for the nexus 10. If you look at the picture above, you will realize that many folders are necessary to handle all devices. The following picture shows an extract of what that means.


As you can see in the device overview picture, no matter how much combinations are possible, there are six different resolutions packages. In reality, there are more but you can break it down like this. A good example is the splash screen mentioned above. Nevertheless, let's take a look at another example. If you have a button, which is 96dp x 96dp in your sw720dp layout, it means, in your 1280x720px picture package you have a 96x96px picture. In your 2560x1600px picture package, you have the same button picture with 192x192px in physical size.

That means, if you have a designer asking for physical picture sizes, you know what`s the answer. It is still a bit more complicated since you have to create flexible layouts using nine-patch images and resizing imageviews, but you have at least a good starting point, now. 

If there are just six different picture size packages and dozens of drawable folder, is it necessary to duplicate each picture multiple times? This would blow up the apk size and that would lead to other problems. So the answer is no, you don`t have to duplicate all pictures. You can use xml drawables to avoid this. For example, instead of putting your button.png (192x192px) in your drawable-sw720dp-xhdpi folder and referencing it from your layout put a button.xml in this folder. The following xml shows an example button using states.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
              android:drawable="@drawable/button_pressed_192" />
    <item android:state_focused="true"
              android:drawable="@drawable/button_focused_192" />
    <item android:drawable="@drawable/button_192" />
</selector>

There are plenty of different xml drawables. The android documentation tells you all you need to know. The original png files goes into the drawable-nodpi folder and that`s it.

Everything works well until you try to upload this application. For some unknown reason google play has a problem with a xml drawable icon. Again everything works fine and every tested device uses it`s desired icon but only the upload fails. The workaround is to duplicate the icon.png and put it in each drawable folder. Sad but the only way to get it working. 

That`s one way to build your android user interface. There might be others. Leave a comment and let me know what you think.

1 comment: