2011-05-02

在 Android 裡使用標籤式頁面

Android 標籤式頁面由 TabHost 負責,TabHost 繼承自 FrameLayout,由負責標籤的 TabWidget 與內容的 FrameLayout 構成。

TabWidget 繼承自 LinearLayout,標籤的內容有三種設定方式:
  • 字串
  • 字串與 icon
  • 一個 View
負責內容的 FrameLayout 有三種資料來源:
  • 一個既有的 View
  • 動態建立的 View
  • 一個獨立的 Activity
分別用三個標籤做測試:Home、Info 與 Favourite。

XML layout 設定檔如下:
<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="wrap_content" 
            android:padding="5dp"
            >
            <ScrollView
                android:id="@+id/homeView"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                >
                <TextView
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:text="This is the Home tab from a view id."
                    />
            </ScrollView>
        </FrameLayout>
    </LinearLayout>
</TabHost>
幾個重點:
  • 由 TabHost 組成根元件
  • TabHost 裡由一個 LinearLayout 包含 TabWidget 與 FrameLayout
  • TabHost、TabWidget 與 FrameLayout 的 id 是內定的。
  • ScrollView 是用來示範「一個既有的 View」的資料來源(Home 標籤),一定要放在 FrameLayout 裡
每個標籤需要一個 XML layout 設定檔,Home 標籤的範例 res/drawable/ic_tab_home.xml 如下:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/home"
        android:state_selected="true" />
    <item android:drawable="@drawable/home_g" />
</selector>
要將 home 與 home_g 兩個 icon 放到 res/drawable 裡,另外兩個 Info 與 Favourite 標籤設定檔略過。

Favourite 標籤的 Activity 程式如下:
public class A_Tab_Favourite extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        tv.setText("This is the Favourite tab from a new activity.");
        setContentView(tv);
    }
}
記得要在 AndroidManifest.xml 裡註冊 Activity:
<application 
    android:icon="@drawable/icon" 
    android:label="@string/app_name">
    <activity 
        android:name=".A_Tab" 
        android:label="@string/app_name" 
        android:theme="@android:style/Theme.NoTitleBar">
        ...
    </activity>
    <activity 
        android:name=".A_Tab_Favourite" 
        android:label="@string/app_name"/>
</application> 
順便套用 Theme.NoTitleBar 將頁面的標題列關閉,以節省空間給標籤列。

最後主要的 Activity 如下:
public class A_Tab extends TabActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Resources res = this.getResources();
        TabHost tabHost = this.getTabHost();
        TabSpec spec;
        // Home tab
        spec = tabHost.newTabSpec("home");
        spec.setIndicator("Home", res.getDrawable(R.drawable.ic_tab_home));
        // 一個既有的 View
        spec.setContent(R.id.homeView); 
        tabHost.addTab(spec);
        // Info tab
        spec = tabHost.newTabSpec("info");
        spec.setIndicator("Info", res.getDrawable(R.drawable.ic_tab_info));
        // 動態建立的 View
        spec.setContent(new TabContentFactory() {

            @Override
            public View createTabContent(String tag) {
                TextView tv = new TextView(A_Tab.this);
                tv.setText("This is the Info tab from a TabContentFactory.");
                return tv;
            }
        });
        tabHost.addTab(spec);
        // Favourite tab
        spec = tabHost.newTabSpec("favourite");
        spec.setIndicator("Favourite",
                res.getDrawable(R.drawable.ic_tab_favourite));
        // 一個獨立的 Activity
        spec.setContent(new Intent().setClass(this, A_Tab_Favourite.class));
        tabHost.addTab(spec);
    }
}
每一組標籤與內容由 TabSpec 表示。

沒有留言:

張貼留言