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
@Override
protected 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).