56

The Material Spec shows a disabled button state that looks greyed out.

https://www.material.io/design/components/buttons.html#toggle-button

I am using the MaterialButton from the material components from Android: https://www.material.io/develop/android/components/material-button/

However when setting the button to disabled the color/tint of the button does not change.

<com.google.android.material.button.MaterialButton
    android:id="@+id/disabled_material_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="@string/button_label_disabled"/>

Just not implemented in Material Android Components by default? Does Material Components define a disabled button statelist?

Dr Mido
  • 2,414
  • 4
  • 32
  • 72
lostintranslation
  • 23,756
  • 50
  • 159
  • 262

6 Answers6

87
  1. Create the folder /res/color (in your res directory).
  2. Add a new color resource file here, named something like color_states_materialbutton.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="false"
        android:color="@color/colorDisabled"  />
    <item android:color="@color/colorEnabled" />
</selector>
  1. Create a style in styles.xml with one of the Widget.MaterialComponents.Button styles as its parent and your color state list as the backgrountTint tag:
<style name="MaterialButtonStyle" parent="Widget.MaterialComponents.Button.UnelevatedButton">
        <item name="backgroundTint">@color/color_states_materialbutton</item>
</style>
  1. Set your style on the MaterialButton in your layout:
<com.google.android.material.button.MaterialButton
    style="@style/MaterialButtonStyle"
    android:id="@+id/disabled_material_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:enabled="false"
    android:text="@string/button_label_disabled"/>
tobiasfried
  • 1,689
  • 8
  • 19
  • Thanks. This is the best answer. Also we can use app:backgroundTint="@color/my_color" directly in xml code of button. – Saeid Z Aug 30 '22 at 19:36
  • I recommend using `parent="ThemeOverlay.Material3.Button"` in the style parent to keep button functionality (such as ripple effect) working properly. – Panos Gr Oct 01 '22 at 07:41
23

With the default style Widget.MaterialComponents.Button the default selector used as backgroundTint handles the disabled state without any changes:

It is the default selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="?attr/colorPrimary" android:state_enabled="true"/>
  <item android:alpha="0.12" android:color="?attr/colorOnSurface"/>
</selector>

Just use:

    <com.google.android.material.button.MaterialButton
        android:enabled="false"
        ..>

enter image description here

If you want to change the disabled color you can use a custom selector

    <com.google.android.material.button.MaterialButton
        app:backgroundTint="@color/my_selector"
        ..>

or you can override the colors used in the default selector:

    <com.google.android.material.button.MaterialButton
        android:theme="@style/button_overlay"
        ..>

with:

    <style name="button_overlay">
       <item name="colorOnSurface">@color/my_color</item>
    </style>
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
6
  1. Create a new Android Resource Directory inside your res folder. Give it the name "color" (see attached image).
  2. Create a Color Resource File with the name "button_disabled" (see attached image).
  3. Place the below code into the button_disabled.xml
<?xml version="1.0" encoding="utf-8"?>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:state_enabled="false" android:color="#FD7E14" android:alpha="0.45"   />
            <item android:color="#FD7E14" />
        </selector>
  1. Locate your values/styles.xml and add the below code
<style name="AppMaterialButton" parent="Widget.MaterialComponents.Button.UnelevatedButton">  <item name="android:backgroundTint">@color/button_disabled</item> </style>
  1. Goto your layout/activity_filename.xml file and add this android:enabled="false" to your button widget.
<com.google.android.material.button.MaterialButton
       android:enabled="false"
       android:id="@+id/button_Join"
       style="@style/AppMaterialButton"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:text="next" 
       app:cornerRadius="0dp" />

Android Resource Directory

Create a Color Resource File

Collins USHI
  • 567
  • 7
  • 17
0

you should use a ThemeOverlay and apply the Colored style separately

    <style name="AccentButton" parent="ThemeOverlay.AppCompat.Dark">
         <!-- customize colorButtonNormal for the disable color -->
         <!-- customize colorAccent for the enabled color -->
    </style>

    <Button
        android:id="@+id/login_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fragment_login_login_button"
        android:theme="@style/AccentButton"
        style="@style/Widget.AppCompat.Button.Colored"/>
VIISHRUT MAVANII
  • 11,410
  • 7
  • 34
  • 49
0

Those looking to change icon and text color in button disabled state, here is how we can do steps are almost same for changing background color.

create a file inside color/button_enable_disable_state.xml

 <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@android:color/white" android:state_enabled="true" />
    <item android:alpha=".3" android:color="@android:color/white" />
</selector>

then go to your them or directly apply to your view like below.

  <style name="ButtonStyled" parent="Widget.MaterialComponents.Button">
        <item name="iconGravity">textStart</item>
        <item name="iconPadding">12dp</item>
        <item name="iconTint">@color/button_enable_disable_state</item>
        <item name="android:textColor">@color/button_enable_disable_state</item>
    </style>

and apply to your view if using theme like below

  <com.google.android.material.button.MaterialButton
        android:id="@+id/call_button"
        style="@style/ButtonStyled"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="20dp"
        android:layout_marginBottom="6dp"
        android:enabled="false"
        android:text="Call"
        android:visibility="visible"
        app:icon="@drawable/ic_call_icon"
       />

or directly apply apply to a view like below

 <com.google.android.material.button.MaterialButton
        android:id="@+id/call_button"
        style="@style/ButtonStyled"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="20dp"
        android:layout_marginBottom="6dp"
        android:enabled="false"
        android:text="Call"
        android:visibility="visible"
        android:textColor="@color/button_enable_disable_state"
        app:iconTint="@color/button_enable_disable_state"
        app:icon="@drawable/ic_call_icon"
        />
vikas kumar
  • 10,447
  • 2
  • 46
  • 52
0

One of the best ways to create enable/disable effect is by overriding the MaterialButton class and apply ColorMatrix on it

import android.content.Context
import android.graphics.Canvas
import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import android.util.AttributeSet
import com.google.android.material.button.MaterialButton

class MaterialButtonCustom @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
): MaterialButton(context,attrs,defStyleAttr) {
    var disabled = false
        set(value) {
            field = value
            requestLayout()
        }

    private val paint = Paint()

    init {
        val cm = ColorMatrix()
        cm.set(
            floatArrayOf(
                0.6f, 0.6f, 0.6f, 0f, 0f,
                0.6f, 0.6f, 0.6f, 0f, 0f,
                0.6f, 0.6f, 0.6f, 0f, 0f,
                0f, 0f, 0f, 1f, 0f
            )
        )
        paint.colorFilter = ColorMatrixColorFilter(cm)
    }

    override fun dispatchDraw(canvas: Canvas?) {
        if (disabled) {
            canvas?.saveLayer(null, paint)
        }

        super.dispatchDraw(canvas)

        if (disabled) {
            canvas?.restore()
        }
    }

    override fun draw(canvas: Canvas?) {
        if (disabled) {
            canvas?.saveLayer(null, paint)
        }

        super.draw(canvas)

        if (disabled) {
            canvas?.restore()
        }
    }
}

and inside Activity

class MainActivity : AppCompatActivity() {
    lateinit var btn_plus:MaterialButtonCustom
    var isActive: Boolean = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn_plus = findViewById(R.id.btn_plus)
        setBtnEnabled()
        btn_plus.setOnClickListener {
            isActive = !isActive
            if(isActive){
                setBtnDisabled()
            }else{
                setBtnEnabled()
            }
        }

    }

    private fun setBtnDisabled() {
        btn_plus.disabled = true
    }

    private fun setBtnEnabled() {
        btn_plus.disabled = false
    }
}
Faisal Naseer
  • 4,110
  • 1
  • 37
  • 55