Search code examples
androidandroid-studioandroid-drawable

How to pass parameters in Android drawable


How to pass arguments in the android drawable.

How to acheive the below mentioned code

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="{colorcode}" />
            <stroke android:width="1sp" android:color="{colorcode}" />
            <corners android:radius="15dp" />
        </shape>
    </item>
</selector>

and then from XML file take this drawable passing values for parameters. Something like

<TextView
    android:layout_width="wrap_content"
    android:layout_height="50dp"
    android:layout_marginRight="5dp"
    android:layout_weight="1"
    android:background="@drawable/rounded,{colorCode}"
    android:gravity="center"/>

Solution

  • ShapeDrawable, GradientDrawable & ColorDrawable are direct subclasses of Drawable. You can explicitly cast your drawable to any of the aforementioned subclasses to invoke methods/property access like setColor(int), .paint like the following:

    val drawable: Drawable = (yourDrawable as StateListDrawable).getStateDrawable(0)
    when (drawable) {
        is ShapeDrawable -> {
            (drawable as ShapeDrawable).paint.color = ContextCompat.getColor(mContext, R.color.colorToSet)
        }
        is GradientDrawable -> {
            (drawable as GradientDrawable).setColor(ContextCompat.getColor(mContext, R.color.colorToSet))
            (drawable as GradientDrawable).cornerRadius = 2.0F
        }
        is ColorDrawable -> {
            (drawable as ColorDrawable).color = ContextCompat.getColor(mContext, R.color.colorToSet)
        }
    }
    

    Points to be noted:

    You can use mutate() on this drawable because it returns the same instance of the drawable with the copied constant drawable state. The mutate() method doesn't share its state with any other drawable so it's pretty helpful if you want to keep the drawable as it is & then use it with different states in many places. Here's a great answer to how to use mutate on drawable & save states.

    Additionally, as you mentioned in the comments, to change drawable radius too, use cornerRadii which as per the doc in the given embedded link, returns the radii for each of the 4 corners. For each corner, the array contains 2 values, [X_radius, Y_radius]. The corners are ordered top-left, top-right, bottom-right, bottom-left.