Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ImageButton Icon Tint based on State

Tags:

android

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.

like image 834
LeDon Avatar asked Jan 29 '18 16:01

LeDon


2 Answers

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.

like image 133
derfshaya Avatar answered Oct 17 '22 01:10

derfshaya


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

        ...
like image 21
Shahin Avatar answered Oct 17 '22 01:10

Shahin