Chris Chris - 4 months ago 23
Android Question

Setting padding of a shape resource / GradientDrawable in code

I have an xml file with a selector in it that defines the different states for a button:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/custom_green_button_selected_state" />
<item android:state_enabled="false" android:drawable="@drawable/custom_green_button_disabled_state" />
<item android:drawable="@drawable/custom_green_button_normal_state"/>
</selector>


Then in each of my drawable xmls I have information on how the button looks like this:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient android:type="linear" android:gradientRadius="180"
android:startColor="#6b9f41" android:endColor="#598a3d" />

<corners android:bottomRightRadius="7dp"
android:bottomLeftRadius="7dp" android:topLeftRadius="7dp"
android:topRightRadius="7dp" />
<padding android:left="15dp" android:right="15dp" android:top="10dp"
android:bottom="10dp" />
</shape>


For most of the buttons in my app I just apply the first xml as the background and everything works fine. For a specific button, I'd like to use the same xmls but make the button skinnier by changing the padding of the drawables. I thought I'd try creating a new StateListDrawable in my code and adding a mutate of each of the individual state's drawable xmls, however, these drawables show up as GradientDrawables which doesn't seem to give me access to their padding properties. Any ideas?

Answer

Padding of background drawable are also set by setPadding in View class.

You can set padding by calling setPadding after setBackgroundDrawable.

Here is core/java/android/view/View.java:

/**
 * Set the background to a given Drawable, or remove the background. If the
 * background has padding, this View's padding is set to the background's
 * padding. However, when a background is removed, this View's padding isn't
 * touched. If setting the padding is desired, please use
 * {@link #setPadding(int, int, int, int)}.
 *
 * @param d The Drawable to use as the background, or null to remove the
 *        background
 */
public void setBackgroundDrawable(Drawable d) {
    boolean requestLayout = false;

    mBackgroundResource = 0;

    /*
     * Regardless of whether we're setting a new background or not, we want
     * to clear the previous drawable.
     */
    if (mBGDrawable != null) {
        mBGDrawable.setCallback(null);
        unscheduleDrawable(mBGDrawable);
    }

    if (d != null) {
        Rect padding = sThreadLocal.get();
        if (padding == null) {
            padding = new Rect();
            sThreadLocal.set(padding);
        }
        if (d.getPadding(padding)) {
            setPadding(padding.left, padding.top, padding.right, padding.bottom);
        }
Comments