Daily Archives: Mar 5, 2013

Android Layouts

So today I’ve been wresting with Android layouts to try to achieve a pretty screen layout as part of a project for my Masters. What ought to be really easy given the pre-existing work from Java springs and struts, HTML and CSS as well as iPhone layouts turns out to be a complete pig.

As an example, let me demonstrate the following. I have two images, one is 400×100 pixels and the other is a 100×100 square. What I would like to do is to lay them out so that together, they fill the width of the screen, scaling both as necessary while preserving their aspect ratios.

That is, the first should occupy 80% of the width and the second 20% of the width of the screen. The second should remain square. I want no padding, margins of other wasted space in this layout.

My first foray is to make a horizontal LinearLayout and allocate the appropriate weights to each.

<LinearLayout
   android:orientation="horizontal"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:weightSum="100" >
   <ImageView
      android:src="@drawable/im400x100"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_weight="80"/>
   <ImageView
      android:src="@drawable/im100x100"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_weight="20"/>
</LinearLayout>

The weights of the two components should now be set to 80% and 20% of the containing LinearLayout. Here are the results when displayed on a Nexus 1 (screen size 480×800)

AndLayout1So, we know that the combined width of the two images should be 500 pixels. This is clearly bigger than the 480 pixels allowed on the Nexus 1 screen. So what I’d hoped would happen is that both images would be shrunk enough that they would fit the width. A quick calculation shows that this would mean the 100×100 image would be 96×96 and the 400×100 would be 384×96 pixels. This is not what has happened. It looks as though the 100×100 image has been kept full size and then the 400×100 image has been shrunk to fit the remaining space. Odd!

Let’s see what happens on the Nexus 7 with its 800×1280 screen.

AndLayoutN7_1OK so here the images are spaced out sufficiently to occupy  the width but haven’t been scaled up to fill the available space. further inspection of android documentation suggests that I ought to add some additional attributes to the images to force them to scale so let’s try that.

Here I’ve added scaleType to each of the images. The android documentation derscribes scaleType

On the N7 it doesnt look too bad, in fact it’s done precisely what I wanted it to. Hurrah!

AndLayoutN7_2The images have scaled up to occupy the horizontal real-estate and have maintained their aspect ration. How does this look on the N1?

AndLayoutN1_2Oh dear. This time the images have been scaled down to fit the width but cropped at the edges. Well, I suppose that’s what the docs said. Let’s try again, this time using fitCenter which is supposed to:

Compute a scale that will maintain the original src aspect ratio, but will also ensure that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The result is centered inside dst.

Here’s how that looks on the N7.

AndLayoutN7_3

Well, the ImgeViews have resized correctly (as shown by the blue outlines) but the IMages are steadfastly refusing to resize. On the N1, we get this:

AndLayoutN1_3

Hmmmm…The horizontal ratio between the views looks OK but it’s clear that right hand view hasn’t preserved the aspect ratio and again, the images haven’t resized.

I’ve also tried to make 9patch images for these two images to get them to scale better but to no avail. It seems that as long as the image is set as the src, your choices are to scale it up to fill all the available space and crop it (which works for these images but not for any real image without a plain coloured background) or to scale only one dimension.

Of course the problem here may be that I expect weights and scaling to apply equally well when I scale an image down as when I scale it up. Perhaps using an image that was smaller than the smallest screen width would be the way to go.

Also, I know I can use the image as a background and without any scaling instruction whatsoever, it will expand to fit the available ImageView space but it doesn’t maintain the aspect ratio.

Well, I’ve exhausted my energy here and may have to try to handle this in code. If anyone can shed some light on how to solve this problem (and judging by the threads on StackOverflow it’s not trivial) all help will be gladly received.