Mark Cramer Mark Cramer - 2 months ago 17
Android Question

Disabled button loses pressed state when touched

I'm generating a number of buttons programmatically (some to increase a value while others to decrease a value) that I disable when the value they adjust either reaches a maximum or minimum. (i.e. The 'increase' button is disabled when the maximum is reached while the 'decrease' button is disabled when the minimum is reached.) In addition to disabling, I'm also setting the button state to 'pressed' in order to visually indicate that the limit value has been reached and the button no longer functions.

My button onClickListener for the 'increase' buttons look like this:

increase.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {

// do some stuff

// here I enable the corresponding 'decrease' button because once you increase you can then decrease
setEnabled(decrease, true);

// if the maximum value is obtained, I disable the 'increase' button because you can't go higher
if (value == maximum) {
setEnabled(increase, false);
}
}
});


The corresponding 'decrease' onClickListeners are similar.

Because these button are changing their own state, I need to use a
Handler
to adjust
Button.setEnabled()
and
Button.setPressed()
after a small delay, so that the user's finger doesn't get in the way (see http://stackoverflow.com/a/28788780/852795). Here is the
setEnabled(final Button b, final boolean set)
method that is used above:

private void setEnabled(final Button b, final boolean set) {
Handler refresh = new Handler(Looper.getMainLooper());
refresh.postDelayed(new Runnable() {
@Override
public void run() {
b.setEnabled(set);
b.setPressed(!set);
}
}, 250); // delayed post required to make pressed button accept setPressed()
}


Everything works great, with one small exception: once a user presses the 'increase' button enough times to reach the maximum the button will be disabled and the 'pressed' state will be set to true, however, if it's then pressed one more time, the 'pressed' state will be turned off. Functionally, the button is disabled. I know this because the onClickHandler is not invoked. Why then is my button losing it's 'pressed' state? How can I stop this from happening?

Update: Looking at http://stackoverflow.com/a/8693444/852795 I tried plugging into the
onTouchListener()
in order to 'intercept' the touch that's turning off the pressed state. However, this, too, is not invoked because, I would imagine, the button is disabled.

Egg Egg
Answer

One way to handle this would be to use a StateListDrawable as the background of the button and set the Disabled state to use the same drawable as the Pressed state. This way you could avoid having to set the Pressed state in code.

ie

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
          android:drawable="@drawable/btn_pressed" /> <!-- pressed -->
    <item android:state_enabled="false" android:drawable="@drawable/btn_pressed"/> <!-- disabled (same as pressed) -->
    <item android:state_enabled="true" android:drawable="@drawable/btn_normal"/>
</selector>
Comments