NOTE:

NOTE: Of late, I have been getting requests for very trivial problems that many of you are facing in your day-to-day work. This blog is not to solve your "project" problems - surely not a "Support" site.
I just love to share my knowledge in my spare time and would appreciate any questions or feedback on the articles and code I have shared. I also do appreciate thought-provoking questions that would lead me to write more articles and share.
But please do not put your day-to-day trivial problems here. Even if you do, you most probably would not get a response here.
Thanks

Search This Blog

x

Friday 11 March 2011

TabLayout or Tabbed View | Android Developer Tutorial


This tutorial is about developing a TabLayout  / tabs which is one of the very important ways of providing the UI in Android.  The default Contacts application uses this layout.

For creating a tab Layout, we need to look at 3 new aspects: TabActivity, TabHost and TabWidget.

Let us begin by looking at how we should declare the layout xml.  The root node has to be a TabHost. What is a TabHost and why is it required? It is nothing but a container for the tabbed view we want to create. It provides methods to add the tabs, remove them and to bring focus to a specific tab etc.

Within this, we need to have a two objects: TabWidget and a FrameLayout.

The TabWidget itself does not do much except contain a list of tab labels that exist within the parent TabHost.  Basically it is nothing but a set of labels that the user clicks in order to select a specific tab. The actual content of each tab is to be held by the 2nd object in the TabHost i.e. a FrameLayout. Hence both the TabWidget and FrameLayout need to be present on each tab. And in order to align htme one after another, we embed them into a LinearLayout.

Hence the layout XML would be like this:

<TabHost
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@android:id/tabhost"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      >
<LinearLayout
      android:id="@+id/LinearLayout01"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:orientation="vertical">
<TabWidget
      android:id="@android:id/tabs"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"></TabWidget>
<FrameLayout
      android:id="@android:id/tabcontent"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"></FrameLayout>

</LinearLayout>
</TabHost>

Now, we will move on to the coding of activities for a Tabbed Layout.

In the application, I want to have 3 tabs. So how do I do it?

Each of the tabs can have either a View, launch an activity by passing an intent or create a view dynamically by using TabHost.TabContentFactory. I have chosen to show only activities in all my tabs.

So, how many activities do you think we need? 3? Sorry 4! There needs to be a main or the parent activity that would display the whole tabbed view and one activity in each of the tabs.

Now let us look at developing the main activity. This has to extend the TabActivity.  This is no different from an Activity except for the additional ability to handle multiple embedded activities or views.

So here is the main class declaration:

public class TabLayoutSample extends TabActivity {

Let us see now, how to create the first tab.

First, we need to get a handle to the TabHost that we have declared in the XML layout file, so that we can add tab activities into it. Here is the code for the same:

      TabHost tabHost = getTabHost();  // The activity TabHost

Into this TabHost, we need to add the tab. How can we? TabHost provides an inner class called TabSpec that allows you to create a tab, populate its contents and add it as a tab to the TabHost.  See how it is done:

TabHost.TabSpec spec; 

// Create an Intent to launch an Activity for the tab (to be reused)
      intent = new Intent().setClass(this, WelcomeActivity.class);

      // Initialize a TabSpec for each tab and add it to the TabHost
      spec = tabHost.newTabSpec("welcome").setIndicator("Welcome",
                          res.getDrawable(R.drawable.tab_welcome))
                      .setContent(intent);
      tabHost.addTab(spec);

In the first line above, we are creating a spec variable of type TabSpec. Then we are creating an intent that would be forming the content of the first tab. Then, we associate it with the TabSpec.

Since, each tab should have a tab indicator, content and a tag to keep track of it, it is achieved through setIndicator(..) method. Even the image that should be shown in the tab at the top is set through the same method’s 2nd parameter res.getDrawable(R.Drawable.tab_welcome). What is this and how did I set the image?

This part is a long set of steps but very easy to do. Create two images one in light color and one in dark color. Call them as welcome.png and welcome_sepia.png. Copy them into the /res/drawable-mdpi folder.  The, you need to create a state-list drawable that specifies which image to use for each tab state:

[A StateListDrawable is a drawable object defined in XML that uses a several different images to represent the same graphic, depending on the state of the object. For example, a Button widget can exist in one of several different states (pressed, focused, or neither) and, using a state list drawable, you can provide a different background image for each state.]

So, here is the tab_welcome.xml:

<?xml version="1.0" encoding="UTF-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- When selected, use grey -->
    <item android:drawable="@drawable/welcome"
          android:state_selected="true" />
    <!-- When not selected, use white-->
    <item android:drawable="@drawable/welcome_sepia" />
</selector>

This XML is describing which welcome image to show when the tab is selected and which to show when the tab is not selected.  This XML too needs to be created in the same folder - /res/drawable-mdpi.

Once all of this is done, when setIndicator("Welcome",                     res.getDrawable(R.drawable.tab_welcome))is called, the image associated with the tab is shown correctly based on the state.

Then, the last part of the tabSpec call is associating the activity that should be shown in the content of the activity. For this, I have created a new Intent which invokes an Activity – ‘WelcomeActivity.class’.  this implies that the WelcomeActivity.class is already created and available. In this case, it just contains a welcome message to be shown.

Once such a spec is created, I add it to the TabHost through the addtab(…) method of the TabHost.
I have repeated the above to show existing “contacts” in the next tab and then the “top links” in the third tab. You can get the complete code for the same here.