1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
page.title=Tab Layout
parent.title=Hello, Views
parent.link=index.html
@jd:body
<p>To create a tabbed UI, you need to use a {@link android.widget.TabHost} and a {@link
android.widget.TabWidget}. The {@link android.widget.TabHost} must be the root node for the layout,
which contains both the {@link android.widget.TabWidget} for displaying the tabs and a {@link
android.widget.FrameLayout} for displaying the tab content.</p>
<p>You can implement your tab content in one of two ways: use the tabs to swap
{@link android.view.View}s within the same {@link android.app.Activity}, or use the tabs to change
between entirely separate activities. Which method you want for your application will depend on your
demands, but if each tab provides a distinct user activity, then it probably makes sense to use
a separate {@link android.app.Activity} for each tab, so that you can better manage the application
in discrete groups, rather than one massive application and layout.</p>
<p>In this tutorial, you'll create a tabbed UI that uses a separate {@link
android.app.Activity} for each tab.</p>
<ol>
<li>Start a new project named <em>HelloTabWidget</em>.</li>
<li>First, create three separate {@link android.app.Activity} classes in your project:
<code>ArtistsActivity</code>, <code>AlbumsActivity</code>, and <code>SongsActivity</code>. These
will each represent a separate tab. For now, make each one display a simple message using a {@link
android.widget.TextView}. For example:
<pre>
public class ArtistsActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textview = new TextView(this);
textview.setText("This is the Artists tab");
setContentView(textview);
}
}
</pre>
<p>Notice that this doesn't use a layout file. Just create a {@link
android.widget.TextView}, give it some text and set that as the content. Duplicate this for
each of the three activities.</p>
<li>You're going to need an icon for each of your tabs. And for each one, you should create an
image for two different states: one for when the tab is selected, and one for when it is not. The
general design recommendation is for the selected tab icon to be a darker color (grey), and the
non-selected icon to be lighter (white). For example:
<p>
<img src="images/ic_tab_artists_white.png" title="ic_tab_artists_white.png" alt="" />
<img src="images/ic_tab_artists_grey.png" title="ic_tab_artists_grey.png" alt="" />
</p>
<p>Copy these images for use in this tutorial. Save them into your project
<code>res/drawable/</code> directory. You now need to create a {@link
android.graphics.drawable.Drawable} with XML that specifies which image
to use for each state. Create a new file in <code>res/drawable/</code> named
<code>ic_tab_artists.xml</code> and insert the following:</p>
<pre>
<?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/ic_tab_artists_grey"
android:state_selected="true" />
<!-- When not selected, use white-->
<item android:drawable="@drawable/ic_tab_artists_white" />
</selector>
</pre>
<p>This is an XML definition for a {@link android.graphics.drawable.Drawable}, which you will
reference as the image for a tab. When the image state changes, the image will automatically
switch between the images defined here.</p>
<li>Open the <code>res/layout/main.xml</code> file and insert the following:
<pre>
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android;padding="5dp" />
</LinearLayout>
</TabHost>
</pre>
<p>This is the layout that will display the tabs and provide navigation between each {@link
android.app.Activity} created above.</p>
<p>The {@link android.widget.TabHost} requires that a {@link android.widget.TabWidget} and a
{@link android.widget.FrameLayout} both live somewhere within it. To position the {@link
android.widget.TabWidget} and {@link android.widget.FrameLayout} vertically, a {@link
android.widget.LinearLayout} is used. The {@link android.widget.FrameLayout} is where the content
for each tab goes, which is empty now because the {@link android.widget.TabHost} will automatically
embed each {@link android.app.Activity} within it.</p>
<p>Notice that the {@link android.widget.TabWidget} and the {@link android.widget.FrameLayout}
elements have the IDs {@code tabs} and {@code tabcontent}, respectively. These names
must be used so that the {@link android.widget.TabHost} can retrieve references to each of
them. It expects exactly these names.</p>
</li>
<li>Now open <code>HelloTabWidget.java</code> and make it extend {@link
android.app.TabActivity}:</p>
<pre>
public class HelloTabWidget extends TabActivity {
</pre>
</li>
<li>Use the following code for the {@link android.app.Activity#onCreate(Bundle) onCreate()}
method:
<pre>
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources(); // Resource object to get Drawables
TabHost tabHost = getTabHost(); // The activity TabHost
TabHost.TabSpec spec; // Resusable TabSpec for each tab
Intent intent; // Reusable Intent for each tab
// Create an Intent to launch an Activity for the tab (to be reused)
intent = new Intent().setClass(this, ArtistsActivity.class);
// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("artists").setIndicator("Artists",
res.getDrawable(R.drawable.ic_tab_artists))
.setContent(intent);
tabHost.addTab(spec);
// Do the same for the other tabs
intent = new Intent().setClass(this, AlbumsActivity.class);
spec = tabHost.newTabSpec("albums").setIndicator("Albums",
res.getDrawable(R.drawable.ic_tab_albums))
.setContent(intent);
mTabHost.addTab(spec);
intent = new Intent().setClass(this, SongsActivity.class);
spec = tabHost.newTabSpec("songs").setIndicator("Songs",
res.getDrawable(R.drawable.ic_tab_songs))
.setContent(intent);
tabHost.addTab(spec);
tabHost.setCurrentTab(getIntent());
}
</pre>
<p>This sets up each tab with their text and icon, and assigns each one an {@link
android.app.Activity}.</p>
<p>A reference to the {@link android.widget.TabHost} is first captured with {@link
android.app.TabActivity#getTabHost()}. Then, for
each tab, a {@link android.widget.TabHost.TabSpec} is created to define the tab properties. The
{@link android.widget.TabHost#newTabSpec(String)} method creates a new {@link
android.widget.TabHost.TabSpec} identified by the given string tag. For each
{@link android.widget.TabHost.TabSpec}, {@link
android.widget.TabHost.TabSpec#setIndicator(CharSequence,Drawable)} is called to set the text and
icon for the tab, and {@link android.widget.TabHost.TabSpec#setContent(Intent)} is called to specify
the {@link android.content.Intent} to opens the appropriate {@link android.app.Activity}. Each
{@link android.widget.TabHost.TabSpec} is then added to the {@link android.widget.TabHost} by
calling {@link android.widget.TabHost#addTab(TabHost.TabSpec)}.</p>
<p>At the very end, {@link
android.widget.TabHost#setCurrentTab(int)} opens the tab to be displayed by default, specified
by the index position of the tab.</p>
<p>Notice that not once was the {@link android.widget.TabWidget} object referenced. This is
because a {@link android.widget.TabWidget} must always be a child of a {@link
android.widget.TabHost}, which is what you use for almost all interaction with the tabs. So when
a tab is added to the {@link android.widget.TabHost}, it's automatically added to the child
{@link android.widget.TabWidget}.</p>
</li>
<li>Now open the Android Manifest file and add the <code>NoTitleBar</code> theme to the
<em>HelloTabWidget</em>'s
<code><activity></code> tag. This will remove the default application title from the top
of the layout, leaving more space for the tabs, which effectively operate as their own titles.
The <code><activity></code> tag should look like this:
<pre>
<activity android:name=".HelloTabWidget" android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar">
</pre>
</li>
<li>Run the application.</li>
</ol>
<p>Your application should look like this:</p>
<img src="images/hello-tabwidget.png" width="150px" />
<h3>References</h3>
<ul>
<li>{@link android.widget.TabWidget}</li>
<li>{@link android.widget.TabHost}</li>
<li>{@link android.widget.TabHost.TabSpec}</li>
<li>{@link android.widget.FrameLayout}</li>
</ul>
|