Monday 11 May 2015

Introduction to android styles and themes part II

INTRODUCTION TO ANDROID STYLES AND THEMES PART II
In the first part of this series, we covered:
1.      What are styles and themes and their difference
2.      How a programmer can create a style
3.      Inheritance
In this post we shall cover:
1.      Inheritance of system styles
2.      Themes



INHERITANCE OF SYSTEM STYLES
Inheriting system styles in android works no differently from inheriting custom styles. You only have to change the way you communicate the parent-child relationship to android.

While inheriting custom styles, we used the notation
parentStyle.childStyle
Here, childStyle will use all attributes of parentStyle and can define its own as well to override parentStyle’s attributes.
Then you’d reference the childStyle with the whole notation in your layouts like so:
style=”@style/parentStyle.childStyle”

NB. In case you have another child style you want to inherit all styles available to childStyle, and may be adds a new attribute, just go ahead and create a new style and call it parentStyle.childStyle.secondChildStyle
 and then reference it from your layouts like so:
style=”@style/parentStyle.childStyle.secondChildStyle”
With this pattern, you can append as many styles as you like.

In the case of system styles, you need to add an extra attribute to your style element.
Let’s dive right into the example and ensure we make our Button and TextView explicitly inherit from the parent Button and TextView styles. 
Actually itis best practice that everytime you are creating a custom style for a view, first inherit all attributes of the parent style in the system and then go ahead and add your own attributes.
Now change your styles.xml to look like so:

styles.xml

xml version="1.0" encoding="utf-8"?>
<resources>
       <style
             name="myButton"
             parent="@android:style/Widget.Button">//inheriting from default button style
                    <item name="android:layout_width">fill_parent</item>
                    <item name="android:layout_height">wrap_content</item>
       </style>
       <style
             name="myTextView"
             parent="@android:style/Widget.TextView">//inheriting from default textview style
                    <item name="android:layout_width">fill_parent</item>
                    <item name="android:layout_height">wrap_content</item>
                    <item name="android:textColor">#FFFF00</item>
       </style>
       <style
             name="myButton.myButtonRedText">
                    <item name="android:textColor">#FF0000</item>
       </style>
       <style
             name="myTextView.myTextViewBlue">
                    <item name="android:textColor">#0000ff</item>
       </style>


At this point we have not changed anything about how our app looks.

Why?

Because we have just explicitly done what android has been doing implicitly (by default). I.e. android has been inheriting all default styles for our Buttons  and TextViews and simply taking our explicitly defined attributes as overrides.
Now you have mastered how to inherit styles attributes from custom styles and default system styles.
Next we are going to look at android themes.

THEMES

As defined in part I of this series, a theme is a set of styles which determine the visual representation of your app (how your app looks). I believe the idea is now clearer, since we have just covered styles.
In essence, a theme is no different from a style. A theme is only a set of styles grouped under one parent (the theme).
·        A style and theme are both defined in values/*.xml files with root element resources
·        The child element of root i.e. style works for both styles and themes. The name attribute references either the theme name or the style name. likewise the parent attribute references a theme or a style any of them is inheriting from. Only that of course, a theme inherits from another theme and a style, from another style.
·        The item element references an attribute for both. For a theme, each item element references the name of style resource and for a style, each item element references the name of an attribute.
It will help a lot to familiarize yourself with this themes.xml file, it’s the android default theme for API level 10 and lower.  And this  styles.xml file which defines the global theme styles of android.

How to apply system theme to your application or activity
Unlike a style whose scope is limited to a single view, the scope of a theme spans a whole activity or application.
We ended part I of this series when our app had a dark theme remember?, like so;
 
screen shot with Theme.Black


Notice the dark background (Theme.Black.), for my API level of 8, it’s the default.
When you look into the Themes.xml file, you should see several themes which all inherit Theme e.g. Theme.Light.NoTitleBar etc. Your task is just to familiarize yourself with the themes available for your target API level since each new API level almost ships with new themes. You can actually tell your app to detect the API level and apply a theme accordingly. That is a topic for another post.
Let’s experiment with applying Theme.Light. Just go to your manifest file and add this attribute to the Application element and of course you now know that you can as well choose to apply it to a specific activity element.

android:theme=”@android:style/Theme.Light”

Now reload your app and it should look like so:
screen shot with Theme.Light
xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.simplejavan.theme"
      android:versionCode="1"
      android:versionName="1.0">          
    <uses-sdk android:minSdkVersion="8" />

    <application
       android:icon="@drawable/icon"
       android:label="@string/app_name"
       android:theme="@android:style/Theme.Light">//invoking the theme
        <activity android:name=".ThemeAndStyleActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

Creating a custom theme
Now that we know how to explicitly tell our app to use a specific theme, we are going to create our own theme and make it first inherit from Theme.Light. This will help us understand:
1.      How to create custom themes
2.      How to inherit styles of a system them
3.      How to apply custom themes to activity or application
Navigate to the res/values directory in our ThemeAndStyle project created in part I of this series. Right click and go to New->android xml. And call it themes.
Alternatively, click on the res/values directory and select the android xml icon in your IDE toolbar.
We are going to create 3 separate themes to nail down the idea, however all of them are defined in the same file. Here is the content of themes.xml

xml version="1.0" encoding="utf-8"?>
<resources>
       <style name="Theme.Red" parent="android:style/Theme.Light">
             <item name="android:buttonStyle">@style/redTheme.Button</item>
             <item name="android:textViewStyle">@style/redTheme.TextView</item>
       </style>
       <style name="Theme.Green" parent="android:style/Theme.Light.NoTitleBar">
             <item name="android:buttonStyle">@style/greenTheme.Button</item>
             <item name="android:textViewStyle">@style/greenTheme.TextView</item>
       </style>
              <style name="Theme.Blue" parent="android:style/Theme.Light">
             <item name="android:buttonStyle">@style/blueTheme.Button</item>
             <item name="android:textViewStyle">@style/blueTheme.TextView</item>
       </style>
</resources>

Ignore the dot notation I have used in naming the themes, they really don’t inherit from any custom theme, but are rather used for clarity since we are creating 3 different basic themes.
Notice the inheritance pattern involving the android namespace and the parent attribute.
We are inheriting from Theme.Light. Notice the little tweak we have added to Theme.Green. Theme.Light.NoTitleBar is another system theme that inherits from Theme.Light and just adds a single property i.e. hides the title bar.
Each item element under a theme definition represents a whole style definition, contrary to the styles where an item element represents a single attribute. The style names you are seing in the item element’s are the system names referencing styles for the corresponding views (Button and TextView). You must have noticed that if you took a look at the system themes.xml. The philosophy is simple, we are inheriting a system theme, so each item element gives us an opportunity to override an existing style in the system theme, similar to styles.xml, where we inherit a system style applying to a view and then in each item element, we override a given attribute.
Now the values of our item elements are references to styles we have to define. As you can see, we shall define style attributes for each view under each theme. Interesting right???

To avoid confusion and the extra step of editing the main.xml to change style reference names, create a second styles xml file and call it styles2.xml, below is the content.

xml version="1.0" encoding="utf-8"?>
<resources>
      
       <style name="greenTheme.Button" parent="@android:style/Widget.Button">
             <item name="android:textColor">#00ff00</item>
       </style>
       <style name="greenTheme.TextView" parent="@android:style/Widget.TextView">
             <item name="android:textColor">#00ff00</item>
       </style>
      
      
       <style name="redTheme.Button" parent="@android:style/Widget.Button">
             <item name="android:textColor">#ff0000</item>
       </style>
       <style name="redTheme.TextView" parent="@android:style/Widget.TextView">
             <item name="android:textColor">#ff0000</item>
       </style>
      
       <style name="blueTheme.Button" parent="@android:style/Widget.Button">
             <item name="android:textColor">#0000ff</item>
       </style>
       <style name="blueTheme.TextView" parent="@android:style/Widget.TextView">
             <item name="android:textColor">#0000ff</item>

       </style>
</resources>

Ignore the dot notation naming of the styles, I am not inheriting any custom styles here, it’s just any ordinary string  but I wanted the style names to be clear since I have created 3 separate styles corresponding to each theme above.
For the sake of being neat, open our original styles.xml, remove the extra child style definitions as well as any color style attributes. Let us leave this style file strictly for layout attributes such as layout_width and layout_height. Remove also the inheritance and just leave it as an isolated style definition.
 Now our styles.xml looks like so:

xml version="1.0" encoding="utf-8"?>
<resources>
       <style name="myButton">
             <item name="android:layout_width">fill_parent</item>
             <item name="android:layout_height">wrap_content</item>
       </style>
       <style name="myTextView">
             <item name="android:layout_width">fill_parent</item>
             <item name="android:layout_height">wrap_content</item>
       </style>
</resources>

Our theme is now ready for referencing. This is where we shall see how to apply a custom theme to an Application or Activity.
For the case of a custom theme, we eliminate the android namespace and just reference the theme using a style reference like so:

xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.simplejavan.theme"
      android:versionCode="1"
      android:versionName="1.0">           
    <uses-sdk android:minSdkVersion="8" />

    <application
       android:icon="@drawable/icon"
       android:label="@string/app_name"
       android:theme="@style/Theme.Red">
        <activity android:name=".ThemeAndStyleActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

In this code, we have referenced Theme.Red, you can go ahead and test with Theme.Green and Theme.Blue.
Below are my screen shots
Theme.Green

Theme.Blue
Theme.Red


I believe you now have a firm understanding of  inheriting system styles, how themes are created and applied.

In part III and the last part of this series, we are going to look at switching themes programmatically and then see how to use simple and complex colors to give a powerful visual to our user interface.


No comments:

Post a Comment