I create things. I blog about it. Sometimes.

9 May 2015

A Solution to the ImageButton Problem

tl;dr Below, you can grab a simple Java class that makes all the ImageButtons in your Android app have a nice pressed and disabled state.

These days, Android provides a lot of neat tools to set up layouts, manage assets and style views. However, creating a consistent feel of buttons (specifically ImageButtons) across an app is still not an easy task and may require you to create a lot of redundant assets and XML code.

Suppose I want the following look for a Facebook-Login button:

The pattern that is used here is actually rather simple: When pressed, dim the image down by 50%, when disabled, dim it up by 50%. In fact, I would like to have this same behavior for any button in my app.

While other operating systems like iOS automatically provide a visually intuitive appearance for the pressed and disabled state of image buttons, Android does not. In theory, you would have to style each and every button with a state list drawable XML, like so:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/b_login_facebook_disabled" android:state_enabled="false"/>
    <item android:drawable="@drawable/b_login_facebook_pressed" android:state_enabled="true" android:state_pressed="true"/>
    <item android:drawable="@drawable/b_login_facebook" android:state_enabled="true"/>
</selector>

Not only would you have to create such a file for each image button in your app, but you’d also have to provide three images (one for each state), which unnecessarily bloats your assets.

The actual problem in creating the look described above is that there is no way to influence the alpha value of your foreground image in the state list XML. If you roam about on StackOverflow, you’ll find different suggestions on how to solve this problem, including wrapping each button in a LinearLayout (yikes) or manually setting an OnTouchListener for each button (ouch).

I didn’t quite like either of them, so I went ahead and created PressableImageButton. It inherits Android’s ImageButton and simply alters the background color and foreground alpha when the button is pressed or disabled. Once you add this class to your project, you only need to change your ImageButton XML tags to .PressableImageButton, like so:

<com.your.project.PressableImageButton
    android:id="@+id/bLoginFacebook"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:src="@drawable/b_login_facebook" />

That’s it. No extra layouts, no background state lists, no additional code, nada.

You may

Grab the source over here.

UPDATE 2015-05-24: I enhanced the class to deal with transparent buttons. If you have a button image with transparency and you don’t want the rectangular background to show, add

<com.your.project.PressableImageButton
    android:background="@null" />

to the XML definition of your button. This will cause the underlying background to shine through.