LessRes

Work-in-progress concept of a LESS-style DSL for generating Android resources.

Android theming and styling is an extremely powerful tool when used correctly. However, complex applications can have hundreds of styles scattered throughout tens of resource folders. When altering or debugging these styles it is sometime not always clear where problems are originating.

Cascading style sheets suffer from the same problem and there has been numerous movements over the last few years to attempt to solve this problem. One of the most popular frameworks, LESS, uses a simple, hierarchical DSL while adding new features such as constants and mixins.

By taking a cue from LESS it should be possible to create a more terse DSL which would allow for more effective style management on Android. This file would be parsed at build-time and converted into its respective set of resource folders and files.

Currently this is only being developed as a concept for possible future implementation. Android styling is much more complex than CSS (having things such as inheritance and namespaces) so much care will need to be taken to develop the DSL to be both powerful yet simple to understand and create.

Input
//Declaring styles
~SherlockTheme:
    actionBarStyle : reference
    actionModeStyle: reference

~SherlockActionBar:
    //Enums get bitwise values by default
    displayOptions: showHome, homeAsUp, showTitle
    //You can also explicitly declare values
    navigationMode:
        standard: 0x01
        list    : 0x08
        tabs    : 0x04


//Constants are converted to resources as well
@primary_color: #ffa36e2b
@secondary_color: #ff9adb51
@height: 60dp


//Mixin to add height to a style
.actionheight:
    height: @height


MyTheme:
    //Specify the parent on pre/post API 11
    ^     Theme.Light
    ^-v11 Theme.Holo.Light

    textColorPrimary:   @primary_color
    textColorSecondary: @secondary_color

    actionBarStyle:
        displayOptions: showHome|homeAsUp
        .actionheight

        //Use tabs on large devices
        navigationMode      : list
        navigationMode-large: tabs
  
    actionModeStyle:
        background: @drawable/action_mode
        .actionheight

    buttonStyle:
        background: @drawable/my_button
Output
<!-- values/lessres.xml -->
<resources>
  <declare-styleable name="SherlockTheme">
    <attr name="actionBarStyle" format="reference" />
    <attr name="actionModeStyle" format="reference" />
  </declare-styleable>
  <declare-styleable name="SherlockActionBar">
    <attr name="displayOptions">
      <item name="showHome" value="1"/>
      <item name="homeAsUp" value="2"/>
      <item name="showTitle" value="4"/>
    </attr>
    <attr name="navigationMode">
      <item name="standard" value="1"/>
      <item name="list" value="8"/>
      <item name="tabs" value="4"/>
    </attr>
  </declare-styleable>


  <color name="primary_color">#ffa36e2b</color>
  <color name="secondary_color">#ff9adb51</color>
  <dimen name="height">60dp</dimen>


  <style name="MyTheme" parent="android:Theme.Light">
    <item name="actionBarStyle">@style/MyTheme_actionBarStyle</item>
    <item name="actionModeStyle">@style/MyTheme_actionModeStyle</item>

    <!-- Attributes not in declares so assume android namespace -->
    <item name="android:textColorPrimary">@color/primary_color</item>
    <item name="android:textColorSecondary">@color/secondary_color</item>
    <item name="android:buttonStyle">@style/MyTheme_buttonStyle</item>
  </style>

  <style name="MyTheme_actionBarStyle" parent="android:Widget">
    <item name="displayOptions">showHome|homeAsUp</item>
    <item name="android:height">@dimen/height</item>
    <item name="navigationMode">list</item>
  </style>
  <style name="MyTheme_actionModeStyle" parent="android:Widget">
    <item name="android:background">@drawable/bg_action_mode</item>
    <item name="android:height">@dimen/height</item>
  </style>

  <!-- Automatically inherits from parent theme style -->
  <style name="MyTheme_buttonStyle" parent="android:Widget.Button">
    <item name="android:background">@drawable/my_button</item>
  </style>
</resources>

<!-- values-large/lessres.xml -->
<resources>
  <style name="MyTheme_actionBarStyle" parent="android:Widget">
    <item name="displayOptions">showHome|homeAsUp|showTitle</item>
    <item name="android:height">@dimen/height</item>
    <item name="navigationMode">tabs</item>
  </style>
</resources>

<!-- values-v11/lessres.xml -->
<resources>
  <style name="MyTheme" parent="android:Theme.Holo.Light">
    <item name="actionBarStyle">@style/MyTheme_actionBarStyle</item>
    <item name="actionModeStyle">@style/MyTheme_actionModeStyle</item>

    <!-- Attributes not in declares so assume android namespace -->
    <item name="android:textColorPrimary">@color/primary_color</item>
    <item name="android:textColorSecondary">@color/secondary_color</item>
    <item name="android:buttonStyle">@style/MyTheme_buttonStyle</item>
  </style>

  <!-- Automatically inherits from parent theme style -->
  <style name="MyTheme_buttonStyle" parent="android:Widget.Holo.Button">
    <item name="android:background">@drawable/my_button</item>
  </style>
</resources>