Color State List not recognized in Shape Drawable
Asked Answered
M

3

13

I define following drawable my_background_drawable.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape android:gravity="center"
            android:shape="rectangle">
            <solid android:color="@color/color_stateful" />
        </shape>
    </item>

    <item android:drawable="@drawable/selector_png_drawable" />
</layer-list>

And I also define following color state list resource color_stateful.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true" android:color="#FF00ff00"/>
    <item android:color="#FFff0000"/>
</selector>

When I set given my_background_drawable as a background for some view then I cannot observe any change in color defined in color_stateful.xml for my shape, while the view state is actually changed (selector_png_drawable.xml is an indicator).

However everything is just fine when I modify my my_background_drawable.xml in the following way:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- This doesn't work
    <item>
        <shape android:gravity="center"
            android:shape="rectangle">
            <solid android:color="@color/color_stateful" />
        </shape>
    </item>
-->
    <item>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:state_pressed="true">
                <shape android:gravity="center"
                    android:shape="rectangle">
                    <solid android:color="#FF00ff00" />
                </shape>
            </item>

            <item>
                <shape android:gravity="center"
                    android:shape="rectangle">
                    <solid android:color="#FFff0000" />
                </shape>
            </item>
        </selector>
    </item>

    <item android:drawable="@drawable/selector_png_drawable"" />
</layer-list>

So is it true that color state information is just lost when ColorStateList resource is used within a ShapeDrawable or am I doing it wrong?

Mok answered 17/11, 2011 at 14:58 Comment(0)
T
25

A ColorStateList cannot be passed as an attribute for <solid> in an XML definition, or really any attribute of a <shape>. This attribute is inflated out of the XML as a Color resource and then passed to the Drawable's setColor() method, which only takes a single ARGB value.

There is only one type of Drawable instance that is designed to contain and present multiple items based on state, and that is StateListDrawable, which is what you get when you inflate a <selector>. All other Drawable instances are meant to simply be members of this collection or drawn standalone.

Note also that an inflated <shape> item is actually a GradientDrawable and not a ShapeDrawable. If you check out the inflate() method of GradientDrawable in the source, you can get all the detail you could ask for on how each attribute is used.

HTH!

Tinytinya answered 17/11, 2011 at 15:19 Comment(3)
As of Android Lollipop, this is no longer true and the ColorStateList is parsed correctly.Mauro
Can confirm it works in Lollipop - was really confused why my <21 test device wasn't working properly!Heterochromous
The obvious (and horrendous) alternative for pre-lollipop devices is to create as many <shape>s as there are states, each one only differing by their <solid> color attribute, and replace the original <shape> drawable by a StateListDrawable referencing each <shape>. The atrocity of the thing can be slightly mitigated by using only resource references inside the <shape> elements (no hard-coded values), and one can also have the original <shape> kept in drawable-v21 directory (to possibly fully switch to later). blarghBergschrund
E
2

In fact you can assign a ColorStateList as a solid color inside of the xml of a a shape -> GradientDrawable, but that is only a new feature in Lollipop.

Older versions of GradientDrawable only accept color resources.

Currently working on a compat alternative if you are interested.

Erythroblastosis answered 20/3, 2015 at 14:40 Comment(0)
G
-4

You are doing it wring .... just Replace this

   android:color="@color/color_stateful"

with

android:background="@color/color_stateful"

update:

in your program code in the my_background_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape android:gravity="center"
            android:shape="rectangle">
            <solid android:background="@color/color_stateful" /> <!--this is the chanage i made... here-->
        </shape>
    </item>

    <item android:drawable="@drawable/selector_png_drawable" />
</layer-list>
Gowk answered 17/11, 2011 at 15:23 Comment(1)
There is no such an attribute as android:background in shape drawableMok

© 2022 - 2024 — McMap. All rights reserved.