开发者

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

开发者 https://www.devze.com 2023-01-03 08:32 出处:网络
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:

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开发者_JAVA百科" 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?


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


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.


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 !


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.


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;
            }
        });


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);
}}


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.


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" />


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消