Tags
android, compound, compound drawables, custom-ui, drawable, mozilla, myth, optimization, optimize, performance, textview
Many a times we tend to add an image to a text for a Button
. The pictorial representation of an action is easier for the user to understand and provides a visual identity for the application. In Android, there is a general perception that this has needs a minimum of three views.
<LinearLayout android:orientation="horizontal"> <ImageView ... the icon ... /> <TextView ... the text ... /> </LinearLayout>
However, Android provides a way to add combine these views into a single view — a TextView
. TextViews can optionally support Drawables
in a view. They can be specified in XML or using Java methods. From the likes of it, based on the naming convention used, they wanted an approach to show borders like in HTML. However, they can be hacked to show much more than borders.
<TextView android:text=" ... the text ... " android:drawableLeft="@drawable/_the_icon_" android:drawablePadding="_gap_to_icon"/>
The Drawable can be assigned to any direction, and more than one can be specified at a time. The distance between the drawable and the text is specified by the attribute android:drawablePadding
. Unfortunately, the padding has to be the same on all sides. Also, this padding is different from the TextView’s padding. By default the image is shown at its actual size. What if the icon is huge and we don’t want it to be bigger than the text? Using Drawable’s setBounds(), we can set the size of the Canvas
to use to render the Drawable. A drawable that is assigned as a compound drawable for a TextView should have its bounds set before being specified as one. The standard Android’s launcher uses this approach to show the icons with the name of the app. The menu items are also rendered in the same way. Though this doesn’t scale well for all purposes, for simpler cases, this reduces the views effectively.
Thanks, nice tutorial !
By the way, to do the same programmatically, using TextView#setCompoundDrawablesWithIntrinsicBounds() avoid the need to call setBounds on the drawable (and you even have the choice to give a drawable or a resource id).
Regards,
Fabien
Ofcourse TextView#setCompoundDrawablesWithIntrinsicBounds() is helpful in not setting the bounds, as it takes the actual bounds of the Drawable. This would work fine, if the image is 32x32dp and would fit perfect with the TextView. However, if you want to shrink a 64x64dp image to 32x32dp and place it with a TextView, you would have to use a setBounds() on the Drawable to shrink the Canvas first, and then set it.
I placed drawableRight to my text view and its layout_width is warp_content, but when text is bigger and shown in multiple line right drawable is position too far from text, is there any solution for this?
The drawables are always aligned to the edge of the container. There is a hacky solution I came up with. I will post it sometime.
Thanks for the reply, if you can give me some guideline for the hack that will be great.
You would have to override getCompoundPaddingLeft()/getCompoundPaddingRight(). That will make the text layout offset its position. Then calculate where to draw the image and draw it.
When you are using setBounds(),aren’t you specifying coordinates for where to draw the image? If i want to shrink the image from 64x64dp to 32x32dp. How do you use setBounds() in this case?
setBounds() will shrink the bitmap to the given bounds.