LeDon
LeDon

Reputation: 549

ImageButton Icon Tint based on State

I am currently trying to implement tinting on some ImageButtons with currently pure white Drawables. The Tint Color should be provided by a StateList and should change depending on the buttons current state. The state list does look like:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#FF0000"/>
    <item android:color="#00FF00" android:state_enabled="false"/>
    <item android:color="#0000FF" android:state_pressed="true" android:state_enabled="true"/>
</selector>

And the layout XML snippet for the button is:

<ImageButton
    android:id="@+id/btnNext"
    style="@style/Widget.AppCompat.Button.Borderless"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="@dimen/vertical_content_padding"
    android:layout_marginEnd="@dimen/horizontal_content_padding"
    android:contentDescription="@string/next"
    android:src="@drawable/ic_chevron_right_white_24dp"
    android:tint="@color/state_btn_tint_light"/>

The default tint from the Color State List is selected and correctly displayed. But disabling the button or pressing it doesn't trigger any color change at all of the Icon. I tried setting it pragmatically too with setImageTintList.

Upvotes: 7

Views: 4643

Answers (2)

derfshaya
derfshaya

Reputation: 338

Your code should work. However, there is one mistake:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#FF0000"/>
    <item android:color="#00FF00" android:state_enabled="false"/>
    <item android:color="#0000FF" android:state_pressed="true" android:state_enabled="true"/>
</selector>

You need to reverse the order of the states.

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#0000FF" android:state_pressed="true" android:state_enabled="true"/>
    <item android:color="#00FF00" android:state_enabled="false"/>
    <item android:color="#FF0000"/>
</selector>

I am not entirely sure how it works internally but it seems to function like If/Else statements. If the first condition fails, then it goes to the second. Since your first item has no conditions, it will always be picked and the others will be ignored, giving the impression that the color state list is not working at all. Hence, always put the color state with the most restrictive conditions first.

Upvotes: 2

Shahin
Shahin

Reputation: 397

I'm going to simplify my answer. hopefully, it helps. You can always enter any color you want in colors.xml right? so let's use it.

you can create an integer array list of the color you want like this

integer[] colors = new integer[]{R.color.white, R.color.black, ...};

Now imageButtons can take background tint like this for example:

imagebutton.setImageTintList(ColorStateList.valueOf(ContextCompat.getColor(mContext,R.color.white)));
  1. Now let's put them together with an animation, create animation method:

public ValueAnimator ColorAnimation(ImageButton imagebutton, int colorFrom, int colorTo){
        ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
        anim .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                imagebutton.setImageTintList(ColorStateList.valueOf((int) animation.getAnimatedValue()));
            }
        });
        anim.setInterpolator(new DecelerateInterpolator());
        anim.setDuration(300); // -- Whatever time
        return anim;
    };

  1. Now, in your activity, you can implement it like this:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout);
        mContext = this;
        ...

        ImageButton myButton = (ImageButton) findViewById(R.id.imagebutton);

        //-- Define All the Colors You want
        integer[] listOfColors = new integer[]{R.color.white, R.color.black, R.color.yellow, R.color.red, R.color.blue};

        //-- With this you can randomly get a color from the list
        int aColor = (int)(Math.random()*listOfColors.length); 

        //-- Your Default imageButton Color
        int DefaultColor = ContextCompat.getColor(mContext,R.color.white);

        myButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ColorAnimation(myButton, DefaultColor, listOfColors[aColor]).start;
                //-- You can even enter whatever color want directly for "colorTo"
                //-- You can Reverse this animation as well
            }
        });

        ...

Upvotes: 1

Related Questions