Tuesday, 28 September 2010

The art of scalable Android Layouts

One of the harder things to figure-out in Android, is how to do nice layouts that work well on different screen sizes. And, as always, I found it difficult to track-down that information!

The key for me in many circumstances is to position elements in percentage terms, generally using fill_parent; this is the opposite of most of the examples I have seen, which tend to use wrap_content! My approach is to ensure that size is defined in relative terms from the top-down using layout_weight; rather than allowing children to dictate their own size (and thereby mess-up the overall layout) via wrap_content...!

Here is a simple example of my approach.

Imagine you have a screen which you want to split into two panels, aligned horizontally, where you want the right-most panel to take-up around 20% of the screen size.

Create a new layout which is a frame layout. Set layout_width and layout_height to fill_parent. We'll use this for most other elements.

Create a LinearLayout within the frame parent. Set orientation to horizontal. Set layout_width and layout_height to fill_parent.

Create two elements (whatever type you need for your panels, maybe ImageView with a drawable background picture if you're just experimenting) as children of your new LinearLayout. Set both to have layout_width of 0dp and layout_weight of 50. If you want one layout to be wider than the other, simple adjust the weights; the element with the larger weight will be bigger proportionately. Make sure you sent layout_height to be fill_parent; otherwise the panels won't properly fill the screen in different configurations!

Want to split-up your right-hand panel into two vertical elements? Replace your right-hand element with a new LinearLayout. Set layout_width to 0dp, and layout_weight to whatever your previous right-hand element was (e.g. 50). Set orientation to vertical. Set layout_height to fill_parent. Put two new elements (again, maybe ImageViews for example...) in the new LinearLayout; set both to have layout_height of 0dp and layout_weight of 50. If you want one layout to be taller than the other, simple adjust the weights. Make sure you sent layout_width to be fill_parent; otherwise (as before!) the panels won't properly fill the screen in different configurations.

And so on! If you need to use an invisible spacer, you can simply follow the above approach and use an empty LinearLayout with the appropriate layout_weight.

This makes sense once you've tried it out; remember to test the layout you create with a variety of AVD sizes!


domi said...

simply wonderful. do you have an equally elegant solution for scaling fonts?

Pete Cole said...

Probably use sp as your font scaling unit... see also here:

In my opinion, the Android layout -based UI is pretty much a disaster. :)

Steve said...

Nice one! Very helpful!

Kids' Music Town said...

just what the doctor ordered... thanks.

Pete Cole said...

I first posted this nearly 4 years ago, and people are still finding it useful. :)