Search code examples
androidstylesduplication

Avoiding duplicated code in android styles


I have an Android app that supports the api 14 and targets api 21. I have some styles that need to be overided by api 21. What happens is that I need to duplicate all style items just to change one item.

For example:

<!-- values/styles.xml -->

<style name="Widget.HelloWorld.Button">
    <item name="android:textSize">24sp</item>
    <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
</style>

If I want to override just the attribute android:textSize in the api 21 I need to duplicate the item android:drawableLeft too.

So to avoid this I came to a solution. In this example I have three buttons (foo, bar and fancy) with some styles (Widget.HelloWorld.Button.Foo, Widget.HelloWorld.Button.Bar, Widget.HelloWorld.Button.Fancy )

<!-- values/styles.xml -->

<resources>
    <style name="v0.Widget.HelloWorld.Button" parent="Widget.AppCompat.Button">
        <item name="android:textSize">24sp</item>
        <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
    </style>

    <style name="v0.Widget.HelloWorld.Button.Foo" parent="Widget.HelloWorld.Button">
        <item name="android:textColor">#f00</item>
    </style>

    <style name="v0.Widget.HelloWorld.Button.Bar" parent="Widget.HelloWorld.Button">
        <item name="android:textColor">#ff0</item>
    </style>

    <style name="v0.Widget.HelloWorld.Button.Fancy" parent="Widget.HelloWorld.Button">
        <item name="android:textColor">#f0f</item>
    </style>

    <!-- Alias -->
    <style name="Widget.HelloWorld.Button" parent="v0.Widget.HelloWorld.Button" />
    <style name="Widget.HelloWorld.Button.Foo" parent="v0.Widget.HelloWorld.Button.Foo" />
    <style name="Widget.HelloWorld.Button.Bar" parent="v0.Widget.HelloWorld.Button.Bar" />
    <style name="Widget.HelloWorld.Button.Fancy" parent="v0.Widget.HelloWorld.Button.Fancy" />
</resources>

I have prefixed all styles names with the version number of the api that will have impact. Since the values/styles.xml is the default, i prefixed with v0.

Now in the values-v21/styles.xml i can override just the item that i want without duplicating code.

<!-- values-v21/styles.xml -->

<resources>
    <style name="v21.Widget.HelloWorld.Button" parent="v0.Widget.HelloWorld.Button">
        <item name="android:textSize">36sp</item>
    </style>

    <style name="v21.Widget.HelloWorld.Button.Fancy" parent="v0.Widget.HelloWorld.Button.Fancy">
        <item name="android:colorPrimary">@color/primary</item>
    </style>

    <!-- Alias -->
    <style name="Widget.HelloWorld.Button" parent="v21.Widget.HelloWorld.Button" />
    <style name="Widget.HelloWorld.Button.Fancy" parent="v21.Widget.HelloWorld.Button.Fancy" />
</resources>

I want to know what is the cons of this approach.


Solution

  • You can fix the original duplication problem using dimension resources that switch on the version qualifier, then referencing it in the style:

    <!-- values/dimens.xml -->
    <resource>
        <dimen name="hello_text_size">24sp</dimen>
    </resource>
    
    <!-- values-v21/dimens.xml -->
    <resource>
        <dimen name="hello_text_size">36sp</dimen>
    </resource>
    
    <!-- values/styles.xml -->
    <style name="Widget.HelloWorld.Button">
        <item name="android:textSize">@dimen/hello_text_size</item>
        <item name="android:drawableLeft">@android:drawable/ic_menu_delete</item>
    </style>