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 ImageView
s), 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.
In reference to my solution at https://stackoverflow.com/a/18724834/2136792, there are a few things you're missing:
TintableImageView.java
@Overrideprotected void drawableStateChanged() { super.drawableStateChanged(); if (tint != null && tint.isStateful()) updateTintColor();}public void setColorFilter(ColorStateList tint) { this.tint = tint; super.setColorFilter(tint.getColorForState(getDrawableState(), 0));}private void updateTintColor() { int color = tint.getColorForState(getDrawableState(), 0); setColorFilter(color);}
drawableStateChanged() must be overridden for the tint to be updated when the element's state changes.
I'm not sure if referencing a drawable from a drawable might cause an issue, but you can simply move your selector.xml into a folder "/res/color" to reference it with "@color/selector.xml" (aapt merges both /res/values/colors.xml and the /res/color folder).