Edward Dale
Edward Dale

Reputation: 30143

Is there a clickable state for a StateListDrawable?

I'm building a custom view that can optionally be clickable. I'd like to set a background that indicates the clickable state. Usually, I would do this with an XML Drawable implemented something like this:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/white" android:state_enabled="false"/>
    <item android:drawable="@drawable/background_white_grey_spinner_pressed" android:state_pressed="true"/>
    <item android:drawable="@drawable/background_white_grey_spinner_normal"/>
</selector>

Unfortunately, it doesn't look like there's an android:state_clickable or android:state_pressable attribute. This seems like a weird oversight considering there's an android:state_long_pressable. Am I missing something?

Upvotes: 1

Views: 1635

Answers (2)

N-JOY
N-JOY

Reputation: 7635

State "enabled" itself is used when we want to set any drawable to the view when its clickable. So "state_enabled" is used to convey a particular view is clickable.

But we can also create a custom drawable state for a particular view and use it to define stateListDrawable

Please check the steps below to create custom drawable state for a view:

  1. Create attrs.xml in res/values and add below code in it:

    <resources>
        <declare-styleable name="food">
            <attr name="state_clickable" format="boolean" />
        </declare-styleable>
    </resources>
    
  2. Create a Custom View which will honour custom drawable state. Adding a sample custom view class below. We will have to override onCreateDrawableState method and merge the existing drawable state with the new one.

     class CustomButton @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null
     ) : MaterialButton(context, attrs) {
    
     private val STATE_CLICKABLE = intArrayOf(R.attr.state_clickable)
    
    
     override fun onCreateDrawableState(extraSpace: Int): IntArray {
         val drawableStates: IntArray = super.onCreateDrawableState(extraSpace + 1)
         if (this.isClickable) {
             mergeDrawableStates(drawableStates, STATE_CLICKABLE);
             }
             return drawableStates
         }
     }
    
  3. Now we can make use of state_clickable in the stateListDrawable. Refer below:

Create a stateListDrawable in res/drawables/button_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/yourAppPackage">
<item
    app:state_clickable="true"
    android:drawable="@drawable/item_clickable" />
<item
    app:state_clickable="false"
    android:drawable="@drawable/item_non_clickable" />
</selector>

This drawable can now be used as background for custom view

Upvotes: 4

Karol Kulbaka
Karol Kulbaka

Reputation: 1274

You should combine states for single item:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" android:state_enabled="false"/>
<item android:drawable="@drawable/background_white_grey_spinner_pressed" android:state_enabled="true" android:state_pressed="true"/>
<item android:drawable="@drawable/background_white_grey_spinner_normal" android:state_enabled="true" android:state_pressed="false"/>

Upvotes: 2

Related Questions