In my application I have a lot of drawables defined with xml files. For example I have a button defined like that:
button.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Bottom 3dp Shadow -->
<item android:top="3dp">
<shape android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="@color/black_30" />
</shape>
</item>
<!-- green top color -->
<item android:top="3dp" android:bottom="3dp" android:id="@+id/background">
<shape android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="@color/green1" />
</shape>
</item>
</layer-list>
and then I display a button like that:
layout.xml
<Button
android:id="@+id/button"
android:layout_gravity="center"
android:layout_height="60dp"
android:layout_width="fill_parent"
android:textSize="17sp"
android:gravity="center"
android:background="@drawable/button" />
When I navigate in the app, I want to "theme" some views (some colors are changing in function of the context) and to do that I would like to be able to change dynamically the color of the button (green1) at runtime.
1) One first nice approach would be to change the color definition in button.xml
with an ?attr/my_color
. And then define the different color values I need in the theme file style.xml
. Then at runtime, I can switch to the desired theme and that will work. The complete steps are here:
How to reference colour attribute in drawable?
The issue is that it works on Android 5 but not on Android 4 ( and I need to support this version) (we get an android.view.InflateException: Binary XML file line #2: Error inflating class <unknown>
)
2) The second approach is to load the drawable in the code and then use setColor
to change the color of the drawable: (written in Xamarin.Android but I am sure that you will understand the corresponding Java version)
LayerDrawable button = (LayerDrawable)Resources.GetDrawable(Resource.Drawable.normal_question_button);
GradientDrawable background = (GradientDrawable)button.FindDrawableByLayerId(Resource.Id.background);
background.SetColor(Android.Graphics.Color.Red.ToArgb());
The good things is that it's works... but randomly... Sometimes when I am displaying the button again, it's still the original green that is displayed. Sometimes, it's the new color... And once I have one of the both behaviour, the same color can stay many time and suddenly it changes again to the correct one.
Someone could explain this? Is there some caching on drawables that can gives that kind of issue?
3) I was thinking about a third solution: dynamically change the color defined in colors.xml
(where green1
is defined) but it doesn't seem possible