Let's say I have a simple shape drawable that draws a ring as follows:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true"
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="36"
android:useLevel="false" >
<gradient
android:centerColor="@android:color/holo_blue_bright"
android:centerY="0.001"
android:endColor="@android:color/holo_blue_dark"
android:gradientRadius="202.5"
android:startColor="@android:color/transparent"
android:type="radial"
android:useLevel="false" />
</shape>
And I apply this shape as a view background as follows:
<View
android:layout_width="96dp"
android:layout_height="96dp"
android:padding="16dp"
android:background="@drawable/custom_shape" />
The exact details of the shape are not relevant for this question - just suffice to say I have a shape. Now, I don't want to hard-code the various parameters for the shape. Let's take thicknessRatio
as an example. If i wanted the thickness ratio to change depending on say, screen configuration, I'd of course use an integer resource as follows. I'd have a values.xml with the following:
<item name="thickness_ratio" type="integer" format="integer">56</item>
And then, android:thicknessRatio="@integer/thickness_ratio"
.
So far, so good. Now, I also want to have two "flavors" of my my shape drawable - a "large" one and a "small" one, and I wish to query the thickness ratio depending not on configuration, but on the style applied to the View. Which is what styles and themes are for. So, here's what I tried:
Step 1: Declare an attribute for thickness ratio (attrs.xml):
<resources>
<attr name="thicknessRatio" format="reference" />
</resources>
Step 2: Declare two styles utilizing this attribute (styles,xml):
<style name="CustomShapeSmall">
<item name="thicknessRatio">@integer/thickness_ratio_small</item>
</style>
<style name="CustomShapeLarge">
<item name="thicknessRatio">@integer/thickness_ratio_large</item>
</style>
Step 3: Define the two integers in values.xml:
<item name="thickness_ratio_small" type="integer" format="integer">32</item>
<item name="thickness_ratio_large" type="integer" format="integer">56</item>
Step 4: Query the custom attribute in the Shape Drawable:
android:thicknessRatio="?attr/thicknessRatio"
Step 5: Apply the desired style to the View
:
<View
android:layout_width="96dp"
android:layout_height="96dp"
android:padding="16dp"
style="@style/CustomShapeSmall"
android:background="@drawable/custom_shape" />
Unfortunately, this does not work. I get the following exception:
Caused by: android.content.res.Resources$NotFoundException: File res/drawable/custom_shape.xml from drawable resource ID #0x7f020000
at android.content.res.Resources.loadDrawable(Resources.java:2091)
at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
at android.view.View.<init>(View.java:3364)
at android.view.View.<init>(View.java:3293)
... 28 more
Caused by: java.lang.NumberFormatException: Invalid float: "?2130771969"
at java.lang.StringToReal.invalidReal(StringToReal.java:63)
at java.lang.StringToReal.parseFloat(StringToReal.java:310)
at java.lang.Float.parseFloat(Float.java:300)
at android.content.res.TypedArray.getFloat(TypedArray.java:287)
at android.graphics.drawable.GradientDrawable.inflate(GradientDrawable.java:827)
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:901)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:837)
at android.content.res.Resources.loadDrawable(Resources.java:2087)
From the exception stack trace, it appears that the line android:thicknessRatio="?attr/thicknessRatio"
resolves to a question mark followed by the integer value of R.attr.thicknessRatio
- however no further resolution is performed to actually query the value of this attribute.
What am I missing here?
EDIT:
Here is the complete github project for this issue.