How do I change the tint of an ImageButton on focus/press

AndroidImageSelectorImagebuttonTint

Android Problem Overview


I have an ImageButton in my app and I need to change the tint of the image when the button is pressed/focused. I have the ImageButton set to get its src from an XML file which as follows:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<!-- pressed -->
	<item 
		android:state_pressed="true"
		android:tint="@color/black"
		android:drawable="@drawable/search"
		/>
	
	<!-- focused -->
	<item 
		android:state_focused="true"
		android:tint="@color/black"
		android:drawable="@drawable/search"
		/>
	
	<!-- default -->
	<item
		android:tint="@null"
		android:drawable="@drawable/search"
		/>

</selector>

However the tint isn't applied when the ImageButton is pressed or focused - the image just displays as normal. The color black is defined as #000000 as always. Any ideas?

Android Solutions


Solution 1 - Android

You can change the tint, quite easily in code via:

ImageButton button = (ImageButton) this.findViewById(R.id.button_i_want_to_modify);
button.setColorFilter(Color.argb(255, 255, 255, 255)); // White Tint

Hope it helps.

JS

Solution 2 - Android

Here is how to do it using just xml. In your drawable folder create a selector. Eg: touch_selector.xml

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

    <!-- State when a row is being pressed, but hasn't yet been activated (finger down) -->
    <item android:state_pressed="true" android:color="@color/semi_slate" />

    <!-- When the view is "activated".  In SINGLE_CHOICE_MODE, it flags the active row
     of a ListView -->
    <item android:state_activated="true" android:color="@color/semi_slate" />

    <!-- Default, "just hangin' out" state. -->
    <item android:color="@android:color/transparent" />
</selector>

In my Image view in xml I set the android:tint attribute to the drawable created above.

android:tint = "@drawable/touch_selector"

The whole code looked like this:

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/poster"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:tint="@drawable/touch_selector" />

This is an all xml solution, to put tint on an ImageView on press or on active. Similar can be done for ImageButton

Note that this only works for API level >= 21.

Solution 3 - Android

Finally I have found a solution for API < 21:

Button more = (Button) findViewById(R.id.more);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    more.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN);
} else {
    Drawable wrapDrawable = DrawableCompat.wrap(more.getBackground());
    DrawableCompat.setTint(wrapDrawable, color));
    more.setBackgroundDrawable(DrawableCompat.unwrap(wrapDrawable));
}

May this help someone not to lose 2 hours !

Solution 4 - Android

I found a way to do this in xml (in api 21 and up at least).

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
        <bitmap
            android:src="@drawable/search"
            android:tint="@color/black"
            />
    </item>
    <item android:drawable="@drawable/search"/>
</selector>

By setting the tint on the bitmap it's possible to reuse the same drawable in xml without having to intercept touches or subclass ImageView or ImageButton.

Once the selector has been created, just apply that as the src of the ImageView or ImageButton.

Solution 5 - Android

bt.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        bt.setColorFilter(Color.argb(255, 255, 255, 255)); // White Tint
                        return true; // if you want to handle the touch event
                    case MotionEvent.ACTION_UP:
                        bt.clearColorFilter(); // White Tint
                        return true; // if you want to handle the touch event
                }
                return false;
            }
        });

Solution 6 - Android

What I'm doing is add a custom button that has the function setColorFilter.

Like this I can use the new button in the xml.

public class CustomButton extends Button {

public CustomButton(Context context) {
	super(context);
}

public CustomButton(Context context, AttributeSet attributes) {
	super(context, attributes);
};

@Override
public boolean onTouchEvent(MotionEvent event) {
	int maskedAction = event.getActionMasked();
	if (maskedAction == MotionEvent.ACTION_DOWN)
		getBackground().setColorFilter(Color.argb(150, 155, 155, 155), PorterDuff.Mode.DST_IN);
	else if (maskedAction == MotionEvent.ACTION_UP)
		getBackground().setColorFilter(null);
	return super.onTouchEvent(event);
}}

and for the ImageButton

public class CustomImageButton extends ImageButton {

public CustomImageButton(Context context) {
	super(context);
}

public CustomImageButton(Context context, AttributeSet attrs) {
	super(context, attrs);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
	int maskedAction = event.getActionMasked();
	if (maskedAction == MotionEvent.ACTION_DOWN)
		setColorFilter(Color.argb(150, 155, 155, 155), PorterDuff.Mode.DST_IN);
	else if (maskedAction == MotionEvent.ACTION_UP)
		setColorFilter(null);
	return super.onTouchEvent(event);
}}

Solution 7 - Android

I noticed there are some requests here for people wanting to know how to do this in XML. It is actually quite simple. This can be accomplished using a layer-list

Your button's drawable (drawable/some_button.xml):

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/some_button_highlighted" />
    <item android:drawable="@drawable/some_button_image" />
</selector>

And this is the highlighted drawable (drawable/some_button_highlighted.xml)

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/some_button_image"/>
    <item>
        <shape>
            <solid android:color="@color/highlighted_button_color" />
        </shape>
    </item>
</layer-list>

Now you can use this in any other xml:

...
android:drawable="@drawable/some_button"
...

I hope this helps someone in the future.

Solution 8 - Android

You can set color (tint) from xml.

Set transparent (android:background="@null") for background then use tint :

<ImageButton
     android:layout_width="wrap_content"
     android:layout_height="fill_parent"
     android:tint="@color/Amber_200"
     android:background="@null"
     android:src="@drawable/back_selector" />

Solution 9 - Android

I have the same issue and I found this solution :

logoImage.setOnTouchListener { v, event ->
            if (event.action == MotionEvent.ACTION_DOWN) {
                if (logoImage.isSelected) {
                    logoImage.setColorFilter(context.getColor(R.color.blue_unselect), PorterDuff.Mode.SRC_IN)
                } else {
                    logoImage.setColorFilter(null)
                }
            } else if (event.action == MotionEvent.ACTION_UP) {
                if (!logoImage.isSelected) {
                    logoImage.setColorFilter(null)
                } else {
                    logoImage.setColorFilter(context.getColor(R.color.blue_unselect), PorterDuff.Mode.SRC_IN)
                }
            } else if (event.action == MotionEvent.ACTION_CANCEL) {
                if (root.isSelected) {
                    logoImage.setColorFilter(null)
                } else {
                    logoImage.setColorFilter(context.getColor(R.color.blue_unselect), PorterDuff.Mode.SRC_IN)
                }
            }
            false
        }

it's working for me.

Solution 10 - Android

As you defined the selector to be the src of the ImageButton Android will AFAIK just take the drawable because that's what matches the type of src. So tint won't be used.

Nevertheless, I had a similar problem: I also tried to use a selector like yours but for the android:tint value of the ImageButton instead of android:src. Of course I omitted the tint values you have in your selector. This would solve your problem, too, because you want to use the same drawable for all states. Curiously I get a NumberFormatException everytime stating that the system was unable to parse 'res/color/tint_selector.xml' (which is indeed my selector) as integer. To be specific my code looks like this:

This is my selector, saved in /res/color/tint_selector.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_pressed="true"
         android:color="#D3D3D3"/> <!-- pressed -->
   <item android:color="#ff000000"/> <!-- default -->
</selector>

And this is the corresponding ImageButton:

<ImageButton android:id="@+id/program_help"
	 android:layout_height="wrap_content" 
     android:layout_width="wrap_content"
	 android:src="@drawable/symbol"
     android:tint="@color/tint_selector">
</ImageButton>

Maybe this helps you a bit although it currently doesn't work.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoseph EarlView Question on Stackoverflow
Solution 1 - AndroidJeffView Answer on Stackoverflow
Solution 2 - AndroidRashi KaranpuriaView Answer on Stackoverflow
Solution 3 - AndroidHenrique de SousaView Answer on Stackoverflow
Solution 4 - AndroidckernView Answer on Stackoverflow
Solution 5 - AndroidFu-Lung ChenView Answer on Stackoverflow
Solution 6 - AndroidElisha SterngoldView Answer on Stackoverflow
Solution 7 - AndroidaeskreisView Answer on Stackoverflow
Solution 8 - Androiduser4813855View Answer on Stackoverflow
Solution 9 - AndroidkomurosView Answer on Stackoverflow
Solution 10 - AndroidubuntudroidView Answer on Stackoverflow