Simplifying layouts with layer-list drawables

a reliable way of positioning drawables within layer-lists

Bartek Lipinski
AndroidPub
4 min readMar 21, 2016

--

I always thought the compound drawable (e.g. drawableLeft) was a nifty feature of the TextView. Unfortunately I remember thousands of times when it wasn’t nifty enough for my needs. There was usually something missing. Something I couldn’t overcome by a proper usage of other attributes (including the drawablePadding).

I was recently developing an app in which the navigation drawer wasn’t following the Material Design Guidelines 100%. To be honest, only the list items were somehow following the material list-item guidelines.

Adapting NavigationView from the Support Design Library to fit my needs wasn’t really an option for me. Writing the navigation menu from the scratch was going to take much less time. At least I thought that at the moment…

I wanted to create a regular NavigationDrawer list item in the most elegant and easy way possible. Just a text with an icon. As simple as that.

The rest of this post describes my struggle on performing that simple task.

If you’re lucky and you know the exact width of your icons, it should be super-easy. E.g. if your icons for the NavigationDrawer are exactly 24dp wide, this:

<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:drawableLeft="@drawable/icon"
android:drawablePadding="32dp"
android:gravity="left|center_vertical"
android:paddingLeft="16dp"
android:text="TextView (with a 24dp icon)"/>

should do the job just fine.

But… if you can’t predict the size of the icon, things will probably get a bit uglier. It’s not something unusual, I’ve been there multiple times. The solution I was ending up with, was usually something like this:

<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">

<ImageView
android:layout_width="72dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="16dp"
android:scaleType="fitStart"
android:src="@drawable/icon"/>

<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical|left"
android:text="ImageView and TextView"/>

</LinearLayout>

It’s working fine, even with icons with different dimensions (as in the example), but I can’t really say that’s an elegant solution. Imagine a layout with 5 or 10 of this sort of list-items stacked on top of each other. There must be a better way!

So I got back to square one (using compound drawable in a TextView) and started messing around with a special drawable.

I thought to myself:

I just have to anchor the icon at the left border of the 72dp space and shift it by 16dp to the right. That doesn’t sound that difficult. I should be able to do that easily with a layer-list!

This is what I came up with:

Two simple layers. The first one that would force the 72dp-wide bounds for the icon. And the second one with the icon itself — shifted. It really worked. It looked promising!

With just a single, simple TextView:

<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:drawableLeft="@drawable/icon"
android:gravity="center_vertical|left"
android:text="Layer-List"/>

Unfortunately this is what I saw on a random Samsung device with 4.X Android:

It wouldn’t respect the first layer at all! Even if I specified a <solid> for it. So I dived back into the layer-list and began a painful process of developing a Samsung-proof solution.

This is what I ended up with:

And it was actually almost correct… almost, because another device (another Samsung… I wonder if that was just a coincidence or not) had a different issue with it:

Some devices seem to be displaying black <shape> if there is no<solid> tag specified within it.

A small change fixes the issue (this time a copyable version):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid
android:color="@android:color/transparent"/>
<size android:width="72dp"/>
</shape>
</item>

<item android:left="16dp">
<bitmap android:gravity="center_vertical|left"
android:src="@drawable/icon"/>
</item>
</layer-list>

And to generalize this whole idea a bit:

If you want to see some of layer-lists that I tried (especially those that weren’t working correctly on all devices) you can see my demo app here.

If you enjoyed this post, please show your support! Recommend, follow, comment. This means a lot!

--

--

Bartek Lipinski
AndroidPub

android engineer @whatnot | ex @reddit | ex @getthefabulous | recovering feature creep 💉 | https://github.com/blipinsk