RSS

Search Engine

Tuesday, September 14, 2010

Adding Tabs Dynamically

The TabWidget in Android is set up to allow you to easily define tabs at compile time. However, sometimes, you want to add tabs to your activity during runtime. For example, imagine an email client where individual emails get opened in their own tab, for easy toggling between messages. In this case, you don’t know how many tabs or what their contents will be until runtime, when the user chooses to open a message.

Fortunately, Android also supports adding tabs dynamically at runtime, and this blog post will show you how.

For compile-time-defined tabs, in your Java code, to set up tabs with contents provided in layout XML, you simply create a TabHost.TabSpec object and call setContent() on it, with the widget ID of the tab’s contents:

  1. TabHost.TabSpec spec=tabs.newTabSpec("buttontab");

  2. spec.setContent(R.id.buttontab);
  3. spec.setIndicator("Button");
  4. tabs.addTab(spec);

Adding tabs dynamically at runtime works much the same way, except you use a different flavor of setContent(), one that takes a TabHost.TabContentFactory instance. This is just a callback that will be invoked — you provide an implementation of createTabContent() and use it to build and return the View that becomes the content of the tab.

Let’s take a look at an example.

First, here is some layout XML for an activity that sets up the tabs and defines one tab, containing a single button:

  1. xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent">
  6. <TabHost android:id="@+id/tabhost"
  7. android:layout_width="fill_parent"
  8. android:layout_height="fill_parent">
  9. <TabWidget android:id="@android:id/tabs"
  10. android:layout_width="fill_parent"
  11. android:layout_height="wrap_content"
  12. />
  13. <FrameLayout android:id="@android:id/tabcontent"
  14. android:layout_width="fill_parent"
  15. android:layout_height="fill_parent"
  16. android:paddingTop="62px">
  17. <Button android:id="@+id/buttontab"
  18. android:layout_width="fill_parent"
  19. android:layout_height="fill_parent"
  20. android:text="A semi-random button"
  21. />
  22. FrameLayout>
  23. TabHost>
  24. LinearLayout>

What we want to do is add new tabs whenever the button is clicked. That can be accomplished in just a few lines of code:

  1. package com.commonsware.android.dynamictab;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.widget.AnalogClock;
  6. import android.widget.Button;
  7. import android.widget.TabHost;

  8. public class DynamicTabDemo extends Activity {
  9. @Override
  10. public void onCreate(Bundle icicle) {
  11. super.onCreate(icicle);
  12. setContentView(R.layout.main);

  13. final TabHost tabs=(TabHost)findViewById(R.id.tabhost);

  14. tabs.setup();

  15. TabHost.TabSpec spec=tabs.newTabSpec("buttontab");
  16. spec.setContent(R.id.buttontab);
  17. spec.setIndicator("Button");
  18. tabs.addTab(spec);

  19. tabs.setCurrentTab(0);

  20. Button btn=(Button)tabs.getCurrentView().findViewById(R.id.buttontab);

  21. btn.setOnClickListener(new View.OnClickListener() {
  22. public void onClick(View view) {
  23. TabHost.TabSpec spec=tabs.newTabSpec("tag1");

  24. spec.setContent(new TabHost.TabContentFactory() {
  25. public View createTabContent(String tag) {
  26. return(new AnalogClock(DynamicTabDemo.this));
  27. }
  28. });
  29. spec.setIndicator("Clock");
  30. tabs.addTab(spec);
  31. }
  32. });
  33. }
  34. }

In our button’s setOnClickListener() callback, we create a TabHost.TabSpec object and give it an anonymous TabHost.TabContentFactory. The factory, in turn, returns the View to be used for the tab — in this case, just an AnalogClock. The logic for constructing the tab’s View could be much more elaborate, such as using ViewInflate to construct a view from layout XML.

Initially, when the activity is launched, we just have the one tab:

Single static tab

But, if we click the button three times, though, we get three new tabs, each containing a clock:

Same activity after three button clicks

While in this case we added new tabs based on button clicks, you could use any sort of event as the trigger for adding a tab: long-tap on a listbox entry, option menu selection, etc.

7 comments:

Jonatas Chagas said...

Hey!

Thats really cool, but I wonder if there is a way to set the style you know? something like style="?textStyle"

Anonymous said...

Hi,

I'm getting an exception at this line of code Button btn=(Button)tabs.getCurrentView().findViewById(R.id.buttontab);

Any idea what I'm doing wrong?

Daniel said...

Nice info... thanks

Free HTC Downloads
You can download free games applications and other stuff for free from http://www.freehtcdownloads.com

Anonymous said...

any one else having a problem with the xml not working correctly. i am getting and error tat says
- Element type "xml" must be followed by either attribute specifications, ">"
or "/>".
- error: Error parsing XML: not well-formed (invalid token)

Anonymous said...

Tabs disappear when I change screen orientation, what's the best way to handle that?

Unknown said...

How i set my own gridcview at analogclock

Anonymous said...

All new android tutorials

VISIT ANDROIDITUTS

http://www.androidituts.com

Post a Comment