How to use selector to tint ImageView?

If you're in API 21+ you can do this easily in XML with a selector and tint:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_activated="true">
        <bitmap android:src="@drawable/ic_settings_grey"
                android:tint="@color/primary" />
    </item>

    <item android:drawable="@drawable/ic_settings_grey"/>
</selector>

I implemented this using DrawableCompat from the Android support-v4 library.

With a regular ImageButton (which subclasses ImageView, so this info also applies to ImageViews), using a black icon from the material icons collection:

<ImageButton
  android:id="@+id/button_add"
  android:src="@drawable/ic_add_black_36dp"
  android:background="?attr/selectableItemBackgroundBorderless"
  android:contentDescription="@string/title_add_item" />

This is the utility method I created:

public static void tintButton(@NonNull ImageButton button) {
    ColorStateList colours = button.getResources()
            .getColorStateList(R.color.button_colour);
    Drawable d = DrawableCompat.wrap(button.getDrawable());
    DrawableCompat.setTintList(d, colours);
    button.setImageDrawable(d);
}

Where res/color/button_colour.xml is a selector that changes the icon colour from red to semi-transparent red when the button is pressed:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item
      android:state_pressed="false"
      android:color="@color/red" />

    <item
      android:color="@color/red_alpha_50pc" />

</selector>

After the ImageButton has been inflated in my activity's onCreate() method, I just call the tintButton(...) helper method once for each button.


I have tested this on Android 4.1 (my minSdkVersion) and 5.0 devices, but DrawableCompat should work back to Android 1.6.