Tab Layout
要创建一个标签式UI,你需要使用 TabHost
和TabWidget 。TabHost必须是XML布局文件的根节点,它包含了一个
TabWidget
和一个 FrameLayout
,分别显示标签和标签内容。
有两种方式来实现标签内容:1. 在同一个Activity里面切换不同的View;2.使用标签在完全独立的Activity之间切换。可以根据你的需求决定选择哪种方式。但是如果每个标签提供的用户活动明显不同,那最好为每个标签提供一个独立的Activity,这样你能很方便的分组管理你的标签内容,而不是只用一个Activity从而乱成一锅粥。
这个教程里,采用第一种方式,每个标签使用一个独立的Activity。
- 创建一个工程:HelloTabWidget
- 然后,创建3个独立的Activity子类:
ArtistsActivity
,AlbumsActivity
, 和SongsActivity
. 每个Activity代表一个标签。现在,让每个Activity用TextView显示一句简单的话。示例: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); } }
注意,这里简单起见,没有使用XML布局文件,只是创建了一个TextView,显示一句简单的话。一共创建3个类似的Activity,记得在Android Manifest文件里登记这3个Activity:
<activity android:name=".ArtistsActivity" /> <activity android:name=".AlbumsActivity" /> <activity android:name=".SongsActivity" />
- 你需要为每个标签准备一个图标。每个图标有两个版本:一个在标签被选中的时候显示,一个在没有被选中的时候显示。通常的设计建议选中的时候显示深色(灰色),没选中的时候显示浅色(白色)。(请参考图标设计指南)。示例:
在本教程里,你可以把这两个图片用在所有的标签上。(但是在开发自己应用时候,必须自己设计图标。)
现在创建一个state-list drawable,来设置每个标签状态显示哪个图片。
- 将图标文件保存到
res/drawable/
目录(补充:高版本里面会有drawable-ldpi,drawable-mdpi, drawable-hdpi,甚至还有drawable-xhdpi,具体怎么用后面的教程会有介绍) - 在
res/drawable/
目录下创建一个新的XML文件ic_tab_artists.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/ic_tab_artists_grey" android:state_selected="true" /> <!-- When not selected, use white--> <item android:drawable="@drawable/ic_tab_artists_white" /> </selector>
这就是一个 state-list drawable, 用来显示标签图标。当标签状态改变的时候,标签图片会自动变换。为每个标签都创建这样一个XML文件,内容类似,只是用到的图标名字根据实际情况修改。
- 将图标文件保存到
- 打开
res/layout/main.xml
修改如下:<?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>
这个布局会显示标签,并能在不同Activity之间提供导航功能。
TabHost里面需要包括一个TabWidget和一个FrameLayout。这里的LinearLayout将TabWidget和FrameLayout按垂直方向排列。FrameLayout里存放标签内容,现在还是空的,TabHost将自动将每个Activity嵌入它里面。
TabWidget和FrameLayout两个元素的ID分别是
tabs
和tabcontent。这两个ID都必须要有,TabHost会通过这个两个ID来引用它们。
- 现在打开
HelloTabWidget.java
并修改其基类为TabActivity
:public class HelloTabWidget extends TabActivity {
- 将
onCreate()
修改为: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); tabHost.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(2); }
以上内容创建各个标签,以及标签上的图标和文字,并给它分配一个Activity。
首先调用getTabHost()方法获得对TabHost的引用。然后,为每个标签创建一个TabHost.TabSpec来设置标签属性。
newTabSpec(String)方法创建一个新的
TabHost.TabSpec,用一个字符串型名字来加以区分。调用TabHost.TabSpec的
setIndicator(CharSequence, Drawable)
方法来设置标签的文字和图标,再调用setContent(Intent)
设置一个Intent来打开对应的Activity。
最后,调用
setCurrentTab(int)
方法来设置默认显示哪个标签,参数是标签的位置索引(从0开始)。
可以看到,TabWidget一次也没使用过,这是因为TabWidget必须总是TabHost的一个元素,你用它来处理几乎所有的标签交互操作。所以当一个标签被加入TabHost以后,它会被自动添加到TabWidget上。
- 现在打开Android Manifest 文件,添加主题
NoTitleBar
HelloTabWidget的<activity>
tag,这个主题不会在最上面显示默认的应用标题,给标签留出更大的空间,每个标签都有自己的标题。<activity>
标识看起来应该像这样:<activity android:name=".HelloTabWidget" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar">
- 运行应用。
你的应用看起来应该像这样(不过你的图标可能不一样):