14

I have a state list drawable, and i want to get a specific drawable from the state list drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:kplus="http://schemas.android.com/apk/res-auto">


    <item kplus:key_type_space_alt="true" android:state_pressed="true" android:drawable="@drawable/space_1_pressed" />
    <item kplus:key_type_space_alt="true" android:drawable="@drawable/space_1_normal" />

    <!-- TopNav keys. -->

    <item kplus:key_type_topnav="true" android:state_pressed="true" android:drawable="@drawable/tab_down" />
    <item kplus:key_type_topnav="true" android:state_selected="true" android:drawable="@drawable/tab_down" />
    <item kplus:key_type_topnav="true" android:drawable="@drawable/tab_normal" />

    <!-- TopRow keys. -->

    <item kplus:key_type_toprow="true" android:state_pressed="true" android:drawable="@drawable/numeric_presseed" />
    <item kplus:key_type_toprow="true" android:drawable="@drawable/numeric_normal" />
</selector>

I select the correct drawable state for each key, something like this:

if (keyIsNumbers) {
    if (KPlusInputMethodService.sNumbersState == 2) {
        drawableState = mDrawableStatesProvider.KEY_STATE_TOPNAV_CHECKED;
    }
}

Now the states are defined like this:

KEY_STATE_TOPNAV_NORMAL = new int[] {keyTypeTopNavAttrId};
KEY_STATE_TOPNAV_PRESSED = new int[] {keyTypeTopNavAttrId, android.R.attr.state_pressed};
KEY_STATE_TOPNAV_CHECKED = new int[] {keyTypeTopNavAttrId, android.R.attr.state_selected};

Now my question is how to extract the correct drawable for each state ? I need to get the 9patch padding of the drawable, because if the state have different padding on 9patch it will get the padding only for the top drawable, and i want to set the padding manually for each key (drawable.getPadding(rect)).

Tazz
  • 781
  • 1
  • 8
  • 23
  • you cannot get the Drawables that form StateListDrawable – pskink Nov 03 '14 at 12:07
  • i was thinking i could get them using the attribute id from stateDrawable[0] u sure its not possible ?:( – Tazz Nov 03 '14 at 12:22
  • what do you need id for? also i dont understand why do you need to access the particular Drawable... – pskink Nov 03 '14 at 12:48
  • i resolved it using ben75 solution, works fine, but i will keep it under supervision to see if something changes. – Tazz Nov 03 '14 at 12:56
  • This answer can help and doesn't use no public Api: https://stackoverflow.com/a/25038966/8716371 – Radost Nov 09 '18 at 12:01

2 Answers2

23

There is no public API to get the drawable from the state.

There are some methods in StateListDrawable but they are @hide with the comment "pending API council".

You can invoke them by reflection... but it's at your own risk !!!. (it may change in future releases)

Those methods are :

Here is how to proceed (exceptions omitted) :

int[] currentState = view.getDrawableState();
StateListDrawable stateListDrawable = (StateListDrawable)view.getBackground();
Method getStateDrawableIndex = StateListDrawable.class.getMethod("getStateDrawableIndex", int[].class);
Method getStateDrawable = StateListDrawable.class.getMethod("getStateDrawable", int.class);
int index = (int) getStateDrawableIndex.invoke(stateListDrawable,currentState);
Drawable drawable = (Drawable) getStateDrawable.invoke(stateListDrawable,index);
ben75
  • 29,217
  • 10
  • 88
  • 134
  • works like a charm for now. I will keep this under supervision to see if it will change in the future. – Tazz Nov 03 '14 at 12:55
  • Thanks man you are genius !! I can give you 100 points for these answer if possible – Sushant Gosavi Jun 14 '17 at 09:16
  • 4
    Just a heads up, this won't work in Android P, https://developer.android.com/preview/restrictions-non-sdk-interfaces.html – behelit Mar 23 '18 at 01:00
  • 2
    The API is finally being made public in Android Q – DrBreakalot May 28 '19 at 09:56
  • Works pretty well! It is a bit worrying using a non-public API though. A small suggestion for the reflection calls is to use `getDeclaredMethod(...)` instead of just `getMethod(...)`. This can throw a NoSuchMethodException (not sure if this is a side-effect of the @hide thing) – Ani Fichadia Apr 24 '20 at 02:28
  • @AniFichadia `getDeclaredMethod(...)` also throws a `NoSuchMethodException` – ben75 Apr 24 '20 at 09:26
0

now it is the way to get specific drawable without reflection:

StateListDrawable pressedDrawable = (StateListDrawable) this.mPressed;
final int state = android.R.attr.state_pressed;
final int index = pressedDrawable.findStateDrawableIndex(new int[]{state});
if (index >= 0) {
    Drawable drawable = pressedDrawable.getStateDrawable(index);
    if (drawable instanceof GradientDrawable) {
        ((GradientDrawable) drawable).setCornerRadius(mRoundConerRadius);
    }
}
VinceStyling
  • 3,707
  • 3
  • 29
  • 44