129

I have a button defined as shown below. When I want to disable it I use my_btn.setEnabled(false), but I would also like to grey it out. How can I do that?

Thanks

<Button android:id="@+id/buy_btn" style="@style/srp_button" />

style/srp_button

<style name="srp_button" parent="@android:style/Widget.Button">
    <item name="android:background">@drawable/btn_default</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">#ffffff</item>
    <item name="android:textSize">14sp</item>
    <item name="android:typeface">serif</item>
    <item name="android:paddingLeft">30dp</item>
    <item name="android:paddingRight">30dp</item>
    <item name="android:paddingTop">5dp</item>
    <item name="android:paddingBottom">5dp</item>
</style>

drawable/btn_default.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/pink" />
    <corners android:radius="6dp" />
</shape>
jul
  • 36,404
  • 64
  • 191
  • 318

9 Answers9

195

You could Also make it appear as disabled by setting the alpha (making it semi-transparent). This is especially useful if your button background is an image, and you don't want to create states for it.

button.setAlpha(.5f);
button.setClickable(false);

update: I wrote the above solution pre Kotlin and when I was a rookie. It's more of a "quick'n'dirty" solution, but I don't recommend it in a professional environment.

Today, if I wanted a generic solution that works on any button/view without having to create a state list, I would create a Kotlin extension.

fun View.disable() {
    getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY)
    setClickable(false)
}

In Java you can do something is similar with a static util function and you would just have to pass in the view as variable. It's not as clean but it works.

Siavash
  • 7,583
  • 13
  • 49
  • 69
  • 4
    I had read that calls to setAlpha are expensive on CPU. Can anyone confirm? – Ali Kazi Jun 15 '16 at 07:37
  • @AliKazi it depends on the type of your `View`. From [this G+ post](https://plus.google.com/+CyrilMottier/posts/DuAZMhFPDjv): "If your View does not contain overlapping drawing commands, `setAlpha()` is optimized away and we simply modify the Paint objects to apply the proper alpha. This happens when `View.hasOverlappingRendering()` returns true. `ImageView`s and `TextView`s with no background drawable are common candidates for this optimization. If you are in this situation, use `setAlpha()` as much as you want.". – Sufian Jun 24 '16 at 09:43
  • 1
    @Sufian Thanks. But to be on a safer side, I relied on a simple StateListDrawable for each button. How I did that, I've posted as a new answer. I've included links to where I learned that alpha is bad for performance. – Ali Kazi Jun 27 '16 at 01:27
  • Visually user-unfriendly – Farid Aug 24 '18 at 14:31
  • that actually visually disable the view. thanks @Siavash – Akash Bisariya Jan 31 '19 at 10:18
  • `setColorFilter` is depricated. – Tim Nov 23 '20 at 05:55
  • Can this be done in the layout instead of programmatically? – IgorGanapolsky Sep 21 '22 at 16:27
  • 1
    @IgorGanapolsky yes look at the answer below (using a selector xml). But if you're just getting into android I highly recommend learning android Compose instead of layouts. Layouts will be obsolete in a couple of years. – Siavash Nov 03 '22 at 21:34
66

You have to provide 3 or 4 states in your btn_defaut.xml as a selector.

  1. Pressed state
  2. Default state
  3. Focus state
  4. Enabled state (Disable state with false indication; see comments)

You will provide effect and background for the states accordingly.

Here is a detailed discussion: Standard Android Button with a different color

Community
  • 1
  • 1
Adil Soomro
  • 37,609
  • 9
  • 103
  • 153
  • So in order to grey it out, I must change the color of the background AND the color of the text in the disable state? There is no way to just add a transparent foreground? – jul Jan 05 '12 at 13:22
  • 3
    Yea! what you will provide for `android:state_disable="true"` it will show the state when the Button is disabled, the easy and recommended way. – Adil Soomro Jan 05 '12 at 13:25
  • 1
    and where can I specify the text color for the disabled state? It seems that only a background can be specified... I asked a new question for that: http://stackoverflow.com/questions/8743584/how-to-set-the-text-style-of-a-button-in-selectors – jul Jan 05 '12 at 13:49
  • 22
    There is no `android:state_disable="true"`, is there? Are you referring to `android:state_enabled="false"`? – caw Jul 12 '13 at 16:08
  • @MarcoW.: yes you are absolutely correct. Apologies for the wrong attribute. – Adil Soomro Jul 15 '13 at 05:34
  • Shouldn't the answer be corrected then? Is this suggestion ok? http://stackoverflow.com/review/suggested-edits/5468508 – brasofilo Aug 05 '14 at 13:42
61

The most easy solution is to set color filter to the background image of a button as I saw here

You can do as follow:

if ('need to set button disable')
    button.getBackground().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
else
    button.getBackground().setColorFilter(null);

Hope I helped someone...

Community
  • 1
  • 1
Woody
  • 1,589
  • 14
  • 16
36

All given answers work fine, but I remember learning that using setAlpha can be a bad idea performance wise (more info here). So creating a StateListDrawable is a better idea to manage disabled state of buttons. Here's how:

Create a XML btn_blue.xml in res/drawable folder:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Disable background -->
    <item android:state_enabled="false"
          android:color="@color/md_blue_200"/>
    
    <!-- Enabled background -->
    <item android:color="@color/md_blue_500"/>
</selector>

Create a button style in res/values/styles.xml

<style name="BlueButton" parent="ThemeOverlay.AppCompat">
      <item name="colorButtonNormal">@drawable/btn_blue</item>
      <item name="android:textColor">@color/md_white_1000</item>
</style>

Then apply this style to your button:

<Button
     android:id="@+id/my_disabled_button"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:theme="@style/BlueButton"/>

Now when you call btnBlue.setEnabled(true) OR btnBlue.setEnabled(false) the state colors will automatically switch.

Aldinjo
  • 394
  • 1
  • 7
  • 21
Ali Kazi
  • 1,561
  • 1
  • 15
  • 22
17

You should create a XML file for the disabled button (drawable/btn_disable.xml)

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/grey" />
    <corners android:radius="6dp" />
</shape>

And create a selector for the button (drawable/btn_selector.xml)

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/btn_disable" android:state_enabled="false"/>
    <item android:drawable="@drawable/btn_default" android:state_enabled="true"/>
    <item android:drawable="@drawable/btn_default" android:state_pressed="false" />

</selector>

Add the selector to your button

<style name="srp_button" parent="@android:style/Widget.Button">
    <item name="android:background">@drawable/btn_selector</item>
</style>
Willy Chen
  • 241
  • 2
  • 3
13

Set Clickable as false and change the backgroung color as:

callButton.setClickable(false);
callButton.setBackgroundColor(Color.parseColor("#808080"));
Saty
  • 1,068
  • 11
  • 24
4

I tried the above solutions but none of them seemed to work for me. I went with the following option:

<!-- button_color_selector.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/colorAccent" android:state_enabled="true"/>
    <item android:color="@color/colorAccentLight" android:state_enabled="false"/>
</selector>
<com.google.android.material.button.MaterialButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:backgroundTint="@color/button_color_selector"
                .../>
Andre Thiele
  • 3,202
  • 3
  • 20
  • 43
2

I used this code for that:

ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
profilePicture.setColorFilter(filter);
Dominik
  • 1,703
  • 6
  • 26
  • 46
0
Button button = (Button)findViewById(R.id.buy_btn);
button.setEnabled(false);
Leon van Noord
  • 868
  • 1
  • 7
  • 24