Saturday, February 18, 2012

Tutorial: Theming an Android App

In my last blog post (Tutorial: Using Layouts in your Android App), I showed how to arrange UI widgets in an Android app using different types of layouts. In this blog post I will show how to change the look and feel of an app using custom widget designs. We will continue using the same app we used in the early tutorial - BMI Calculator.

Here is the look and feel of the app before and after applying our custom theme.

Before Applying the Theme
After Applying the Theme

You can see we have changed the background colors, added a custom title bar, and changed the theme of widgets. We have already talked about changing the background color. So here I will show you how to add a custom title bar and how to change the theme of widgets.

You can use the following links to download the eclipse project and the android app that we are creating in this tutorial.

Download the eclipse project files (zipped) com.blogger.android.meda.bmicalculator-version2.1.zip
Access the Source code from github github repo
Download the free BMI Calculator app (the latest version) from the Android Market. Available in Android Market


Adding a custom Title bar

Before adding a custom title bar, we will remove the default title bar added for our application. This can be easily done by modifying the AndroidManifest.xml in the root directory of the eclipse project. (Have a look at the underlined attribute of the activity element in the following code)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogger.android.meda.bmicalculator"
    android:versionCode="6"
    android:versionName="2.1" >
 
    <uses-sdk android:minSdkVersion="4" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".BMICalculatorActivity" 
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Black.NoTitleBar">

            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>
        </activity>
    </application>
</manifest>
 
Next we add a new linear layout at the top (just after the root linearLayout element) of the res/layout/main.xml file. And inside the layout we will add the project icon and the title.

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorBG" >
 
        <ImageView
            android:id="@+id/test_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dip"
            android:src="@drawable/ic_launcher" />
 
        <TextView
            android:id="@+id/textView0"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dip"
            android:layout_marginLeft="15dip"
            android:layout_marginRight="5dip"
            android:layout_marginTop="9dip"
            android:text="@string/app_name"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="@color/colorFonts" />

    </LinearLayout>


Here the ImageView contain the icon that is shown in the title bar. It is same as the launcher icon in this case (See how to add a launcher icon for the app by following this tutorial, Create Launcher Icon For Your Android App). In the second text view, we show the string "@string/app_name", which is defined in the "res/values/strings.xml" as "BMI Calculator". And the background of the title bar is set by adding the backgroud attribute to the "@color/colorBG" which is again defined in the strings.xml.

These steps would give you the following design to the title of the BMI Calculator App.

Custom Title bar


Theming the Widgets

To get a custom look and feeling for buttons, we can provide custom images for the different states of the button. We will prepare images for the following states of the button.
  • Normal: When the button is neither pressed nor focussed.
  • Pressed: When the button is pressed.
  • Focused: When the button is in focus. Normally this state occurs, when a user select and jump between buttons using array keys in their phone.
Since we have Button and Spinner widgets, we have to create different images for each of these widget types. Not only that, I thought it is better to have different images for two kind of Spinner widgets. Spinners that show the units (in right corner) only have one downward arrow, where as the spinners show the numbers would have two arrow signs.

To prepare the images in photoshop, I started with 50X40 size image, added a rounded rectangle shape, and styled it with bevel and emboss. Here is the set of images I could come up with. (I think they are not that good looking, but just enough for our work).
Set of Images used in theming Widgets

Drawing 9-Patch Images

Before applying these images for the widgets, we should convert them in to a format called 9-patch images. This was necessary because with the different sizes of widgets (and different screen sizes of android phones/tablets), the images may stretch giving a unhandy look.

With the 9-patch format, we can control the stretching by specifying which part should be repeated when the image is stretched. For example in the onesided_spinner_normal.png shown above, we can specify not to stretch the arrow sign part, while stretching the button.

Additionally in 9-patch format, we can specify in which section in the image the text/content should be shown. For example this is useful in images like  onesided_spinner_normal.png. When we apply it to a button, we want the text of the button to not cover its arrow sign.

To create 9-patch images, android SDK provide 9-patch image editor. You can find it in tools/draw9patch (tools/draw9patch.exe) in the android SDK directory.
Lets run the draw9patch editor and open the "onesided_spinner_normal.png" that we prepared earlier.

draw9patch editor
You can see the image is opened in the left side panel. The right hand side panel shows the different looks it will get when it is stretched vertically, horizontally, and diagonally. Here what we do is put some patches (just by clicking) in the border of the image (in the left side panel) as shown below.

Making 9-patch Image (red and blue arrows are added for clarity)
Patches shown in red arrows (top and left borders) are to say that the image should be stretched only in these sections. For example there is only one patch in the top border. That mean when the image is stretched horizontally, the line of pixel below the patch would be repeated and non of the other pixels will be repeated. And the patches in the left border, make sure the arrow sign and the circle will not be stretched. You can see the sample stretched images in the right hand side panel after our patches are applied.

The blue arrows in the above screenshot (bottom and right borders) shows the patches that indicate which part should contain the text (or any other content) of the widget. (Note the patches in the bottom border; we make sure the content will not appear near the arrow sign)

When we save the image, the editor will add 9.png (in this case onesided_spinner_normal.9.png) as the extension of the image. This extension is used by android UI to identify 9-patch images and stretched accordingly. We will convert all the prepared images to 9-patch format.

Copy all the 9-patch images to the res/drawable directory of the project.

Applying Styles to Widgets

To specify the images corresponding to different states (normal, pressed, focussed) of the button widget, we will create an xml called bmi_button.xml with the following content.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_focused="true" 
       android:state_pressed="false" 
       android:drawable="@drawable/button_focused" />

    <item android:state_focused="true" 
       android:state_pressed="true"
       android:drawable="@drawable/button_pressed" />

    <item android:state_focused="false" 
       android:state_pressed="true"
   android:drawable="@drawable/button_pressed" />

    <item android:drawable="@drawable/button_normal" />
</selector>

Here the "@drawable/button_focused" refers to the button_focused.9.png file in the res/drawable directory.

Similar to button, we would prepare two more XML files called bmi_onesided_spinner.xml and bmi_twosided_spinner.xml for each of the spinner types. (The content would be the same as above except the drawable attribute should refer to the corresponding 9-patch images).

Next we have to set the style XMLs we have created here as the backgroud of the widgets. This is simply done by changing or adding the backgroud attribute to the widgets in main.xml (The UI XML). Here is the updated section of the main.xml. (The changes are underlined.)


    <TableLayout
        android:id="@+id/tableLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

 
        <TableRow
            android:id="@+id/tableRow1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dip"
            android:layout_marginRight="5dip"
            android:layout_marginTop="15dip" >
 
            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="5dip"
                android:text="@string/weightLabel"
                android:textAppearance="?android:attr/textAppearanceMedium" />
 
            <Spinner
                android:id="@+id/spinner1"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                android:background="@drawable/bmi_twosided_spinner"
                android:prompt="@string/weightLabel" />
 
            <Spinner
                android:id="@+id/spinner2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dip"
                android:layout_weight="1"
                android:background="@drawable/bmi_onesided_spinner"
                android:drawSelectorOnTop="true"
                android:entries="@array/weightUnitsArray" />
        </TableRow>
 
        <TableRow
            android:id="@+id/tableRow2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dip"
            android:layout_marginRight="5dip"
            android:layout_marginTop="15dip" >
 
            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="5dip"
                android:text="@string/heightLabel"
                android:textAppearance="?android:attr/textAppearanceMedium" />
 
            <Spinner
                android:id="@+id/spinner3"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                android:background="@drawable/bmi_twosided_spinner"
                android:prompt="@string/heightLabel" />
 
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dip"
                android:layout_weight="1" >
 
                <Spinner
                    android:id="@+id/spinner4"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:background="@drawable/bmi_onesided_spinner"
                    android:entries="@array/heightUnitsArray" />
 
                <Button
                    android:id="@+id/button1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignRight="@+id/spinner4"
                    android:layout_below="@+id/spinner4"
                    android:layout_marginTop="15dip"
                    android:background="@drawable/bmi_button"
                    android:onClick="calculateClickHandler"
                    android:text="@string/calculateButton" />

            </RelativeLayout>

        </TableRow>

    </TableLayout>

Here the "@drawable/bmi_button" refers to the bmi_button.xml in the res/drawable directory that we prepared earlier.

That is all you have to do. Now run the app in your phone and check the new look and feel.

New Look and Feel of the app

35 comments:

  1. thanks for sharing! although it looks a little complicated u.u
    btw, i also have a blog and a web directory, would you like to exchange links?? anyway, just let me know

    emily.kovacs14@gmail.com

    ReplyDelete
  2. I have got lots of ideas from this blog which is very useful for me that provide the right way to customize the theme in android app so thanks for that.

    Mobile App Development

    ReplyDelete
  3. There is no doubt that your article is so amzing. Thanks for sharing.

    mobile game developers

    ReplyDelete
  4. your informative information are really very much interesting thus i like this blog very much.

    Best Android Training Institute in Chennai

    ReplyDelete
  5. Wonderful blog.. Thanks for sharing informative blog.. its very useful to me..

    Mobile App Development

    ReplyDelete
  6. Thanks for sharing such a informative code.It will really helpful.

    Mobile app developers in Houston

    ReplyDelete
  7. Thanks for sharing the great blog post with us! It's very useful information for every Android developer.
    Hire Angularjs Developers | Truck Dispatch Software | Taxi App Development

    ReplyDelete
  8. Thank You! For sharing such a great article, It’s been an amazing article. It provides lot’s of information, I really enjoyed to read this, I hope, I will get these kinds of information on a regular basis from your side.
    Apps Development Company in Nigeria
    Apps Development Companies in Tanzania
    Apps Development Company in Ghana

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. WhatsApp Status Video Download :WhatsApp introduced the status feature in 2015, in which we can share images, videos, and gifs as our story for 24 hours. Before this feature, WhatsApp had only text status option in which we can write our bio, but the new status feature is different. The story or status disappears after 24 hours and can’t be archived as still in WhatsApp.

    Boy attitude status video download for whatsApp
    Boy attitude status video download
    Boy attitude status video download

    Most romantic status video download for whatsApp
    Most Romantic status video download
    Most Romantic status video download

    video status download for whatsApp


    we have latest & best collection of video status download for whatsapp

    ReplyDelete
  11. Hi,
    Best article, very useful and well explanation. Your post is extremely incredible.Good job & thank you very much for the new information, i learned something new. Very well written. It was sooo good to read and usefull to improve knowledge. Who want to learn this information most helpful. One who wanted to learn this technology IT employees will always suggest you take Data science course in Pimple Saudagar

    ReplyDelete
  12. This is a nice post in an interesting line of content. Thanks for sharing this post. a great way of bringing this topic to discussion.Cost To Make Ecommerce Mobile App
    Cost To Develop Job Portal App Like Naukri
    Cryptocurrency Development Company

    ReplyDelete
  13. The registrations and auditions for the Bigg Boss 13 are going to start soon. The official list of contestants is not yet announced by the officials.

    Augmented Reality App development

    ReplyDelete
  14. Very Well said totally agree with you thank you for the great share!
    how much does it cost to create an app

    ReplyDelete
  15. Thank You! For sharing such a great article, It’s been an amazing article. It provides lot’s of information, I really enjoyed to read this.

    free ebook for mobile app development

    ReplyDelete
  16. This article is very much helpful and i hope this will be an useful information for the needed one. Keep on updating these kinds of informative things.
    Free guide for age related macular degeneration diseases

    ReplyDelete
  17. You have provided an nice article, Thank you very much for this one. And i hope this will be useful for many people.

    Find Content writers

    ReplyDelete
  18. This article is very much helpful and i hope this will be an useful information for the needed one. Keep on updating these kinds of informative things.

    Eye Health

    ReplyDelete
  19. Thanks for the post,i got lot more ideas.It is so amazing and knowledgeable.I hope its useful for others as well.Data Science is a blend of various tools, algorithms, and machine learning principles with the goal to discover hidden patterns from the raw data.If you are looking for Data Science course visit our site.
    Best Data Science Certification Course in Bangalore

    ReplyDelete
  20. This is a nice post in an interesting line of content. Thanks for sharing this post. a great way of bringing this topic to discussion.
    Cost To Make Ecommerce Mobile App

    ReplyDelete
  21. Nice article I was really impressed by seeing this blog, it was very interesting and it is very useful for me. Informative blog! It was very useful for me. Thanks for sharing.
    Also Visits
    hire android app development company
    Blockchain app development company

    ReplyDelete
  22. Come up with a great learning experience of Azure Training in Chennai, from Infycle Technologies, the best software training institute in Chennai. Get up with other technical courses like Data Science, Selenium Automation Testing, Mobile App Development, Cyber Security, Big Data, Full Stack Development with a great learning experience and outstanding placements in top IT firms. For best offers with learning, reach us on +91-7504633633, +91-7502633633.

    ReplyDelete
  23. This comment has been removed by the author.

    ReplyDelete