131

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> 
1

9 Answers 9

199

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.

Sign up to request clarification or add additional context in comments.

8 Comments

I had read that calls to setAlpha are expensive on CPU. Can anyone confirm?
@AliKazi it depends on the type of your View. From this G+ post: "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. ImageViews and TextViews with no background drawable are common candidates for this optimization. If you are in this situation, use setAlpha() as much as you want.".
@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.
Visually user-unfriendly
@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.
|
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

6 Comments

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?
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.
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: stackoverflow.com/questions/8743584/…
There is no android:state_disable="true", is there? Are you referring to android:state_enabled="false"?
@MarcoW.: yes you are absolutely correct. Apologies for the wrong attribute.
|
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...

4 Comments

This approach has potential, but the resulting color isn't always what you think it'll be. For example, an Orange button with the Gray color multiplied results in a dark red color - not a faded orange.
maybe Mode.SRC_IN should be used instead of the Multiply. See stackoverflow.com/a/17112876/550471
This works, but two colors when mixed turns into another color
Awesome! so clean.
37

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.

Comments

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> 

Comments

13

Set Clickable as false and change the backgroung color as:

callButton.setClickable(false); callButton.setBackgroundColor(Color.parseColor("#808080")); 

Comments

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

Comments

2

I used this code for that:

ColorMatrix matrix = new ColorMatrix(); matrix.setSaturation(0); ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix); profilePicture.setColorFilter(filter); 

Comments

0
Button button = (Button)findViewById(R.id.buy_btn); button.setEnabled(false); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.