I recently learned about a small feature in Android which has been there since API level 1 (the variant that we’ll use has been in there since API 3, but others appeared in API 1): Compound Drawables. In this article we’ll have a look at what they are and see how we can use them to simplify some of our layouts.
Before we start, a little background: Recently I was working on a project where one of my layouts contained typical “icon” configuration (consisting of a graphic with a text label below it), quite similar to what we used in the article on Intelligent Layouts. My layout worked perfectly well, but I updated to ADT 16 and the new Lint tool gave me a warning which I didn’t understand: This tag and its children can be replaced by one
I my code to be free of warnings because they are often indicative of a potential bug or inefficiency, so I wanted to learn what this warning meant in order to eradicate it. First let’s have a look at the block in my XML which caused this warning:[xml]
Which looks like this:
The warning was given on the LinearLayout element. A quick dig through the documentation for TextView lead me to the setCompoundDrawableWithIntrinsicBounds() method which is a method of attaching drawables to a TextView. We can replace the LinearLayout and its two children with a single TextView:[xml]
Then in the onCreate() method of our activity we can assign a drawable to appear above the text:[java] @Override
public void onCreate( Bundle savedInstanceState )
super.onCreate( savedInstanceState );
setContentView( R.layout.main );
TextView tv = (TextView) findViewById( R.id.textView );
R.drawable.ic_launcher, 0, 0 );
setCompoundDrawablesWithIntrinsicBounds() takes four parameters representing drawables which will be placed to the left, above, to the right of, and below the text respectively. In this case we only want an image above the text, so we set the set the second parameter to the drawable we require and the others to 0. There are a couple of variants of the setCompoundDrawables*() method which I won’t cover here, but are easy enough to understand. In addition you can use the setCompoundDrawablePadding() method to apply padding to the drawables.
I won’t bother with a screen capture of this because it is identical to the previous one – it just uses a single Widget in the layout compared to the initial one which used three.
As ever in Android, there are multiple ways of achieving the same result, and we can achieve the same thing purely in layout so that there is no java code required:[xml]
This is almost identical to the previous solution except that we have replaced the id attribute with a drawableTop one. drawableTop is effectively calling setCompoundDrawablesWithIntrinsicBounds() for us, so removing the need for any java.
As well as the simple icon layout that I’ve demonstrated here, there are plenty of other use cases where compound drawables can simplify your layouts. If you use the Lint tool in ADT 16+ you will be alerted to instances where you can make this optimisation. It my only sound like a small improvement to create one Widget instead of three, but if we expand this to the layout that we created in Intelligent Layouts, we would be creating 18 fewer widgets.
This optimisation can also be used in the Views that we create for individual ListView items to make your scrolling smoother – fewer object creations speeds up layout inflation (but always recycle your views as discussed here).
The source code for this article can be found here.
© 2012, Mark Allison. All rights reserved.
Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.