標籤(選項)式佈局(Tab Layout)(基於 API 4 )---- (1)

文章內容



1.  基於平臺版本的標籤應用


2.  把視圖設置爲標籤內容


3.  實現TabHost.TabContentFactory接口


4.  把意圖設置爲標籤內容





1. 基於平臺版本的標籤應用



       隨着android API 標準的不斷更新,創建標籤式佈局應用的方式也發生了變化。在android 1.6(API 4)版本以前(包括API 4),實現標籤佈局應用的代碼需要擴展TabActivity。在android 1.6和android 3.0之間(不包括3.0),則需要引入靜態庫android.support.v4.app擴展其中的FragmentActivity類。它也是那些想要使用支持基於FragmentLoader API的基類。在android 3.0以後,代碼像創建普通活動一樣,擴展Activity類,然後通過ActionBar創建和添加標籤項。


       下面,簡單地介紹一下平臺版本基於API 4(及以前)時創建標籤式佈局應用需要掌握的知識點。


       標籤佈局主要由三部分組成構成,標籤宿主,標籤項和標籤內容。標籤宿主是持有標籤項和標籤內容的載體,也是創建標籤項的發起者。在標籤項上可以添加一個圖標和標記用以追蹤當前的焦點。不同的標籤可以承載不同的內容。而標籤內容則可以根據需要選擇其實現的方式。具體來說,可以採用以下三種方式來實現標籤內容:


       1. 爲標籤內容引用視圖id(setTabContent by view Id);

       2. 通過實現標籤宿主內的標籤內容工廠類(implements TabHost.TabContentFactory);

       3. 爲標籤內容設置意圖來加載活動(setTabContent by intent);


       無論採用哪種方式,都不得不說,實現標籤內容纔是標籤式佈局應用的本質所在。接下來,我們創建一個工程,並以此來逐一說明每種實現標籤內容的方法。

    

       1.   創建一個新的android工程,命名爲HelloTabWidget。

         2.   需要爲每個標籤準備狀態小圖標。一個是在標籤被選中時顯示,另一個則是在未被選中時顯示。通常的設計建議是爲選中的標籤圖標使用深色(灰色),而未被選中的標籤圖標則使用亮色(白色)。例如:


          (未被選中)        (被選中)


          作爲演示,我們爲三個標籤使用同樣的上述圖標(實際開發中應該爲不同的標籤使用不同的自定義圖標)。


        現在,創建一個state-list drawable 資源用來爲每個標籤的狀態指定對應的圖標。


  •          把圖標保存到工程res/drawable/目錄下;
  •         res/drawable/目錄下創建一個XML文件,並命爲ic_tab_artists.xml,且內容如下:

 

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 當標籤被選中時使用灰色圖標 -->
    <item android:drawable="@drawable/ic_tab_artists_grey"
          android:state_selected="true" />
    <!-- 當標籤未選中時使用白色圖標-->
    <item android:drawable="@drawable/ic_tab_artists_white" />
</selector>

       

        關於state-list drawable 資源的創建可以參考:http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList


         準備工作已經做好了。接下來就逐一地使用不同的方法來爲標籤設置內容。


2. 把視圖設置爲標籤內容


        首先,修改res/layout/下面的main.xml文件,修改後內容如下:


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView android:id="@+id/tab_view1"
        android:background="@drawable/blue"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/tabs_1_tab_1"/>

    <TextView android:id="@+id/tab_view2"
        android:background="@drawable/red"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/tabs_1_tab_2"/>

    <TextView android:id="@+id/tab_view3"
        android:background="@drawable/green"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/tabs_1_tab_3"/>

</FrameLayout>

       

         在上述的佈局文件裏,包括了三個文本視圖,目的是用他們來作爲三個標籤項的內容。注意,這三個視圖的位置並沒有指定,因此在切換標籤時,他們的內容將會相互覆蓋。


        然後,實現HelloWidget類,內容如下:


public class HelloTabWidget extends TabActivity {
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        @SuppressWarnings("deprecation")
		TabHost tabHost = getTabHost();
        Resources res = getResources();
        
        LayoutInflater.from(this).inflate(R.layout.main, tabHost.getTabContentView(), true);
         
        tabHost.addTab(tabHost.newTabSpec("tab1")
                .setIndicator("tab1",res.getDrawable(R.drawable.ic_tab_artists))
                .setContent(R.id.view1));
        tabHost.addTab(tabHost.newTabSpec("tab3")
                .setIndicator("tab2" ,res.getDrawable(R.drawable.ic_tab_artists))
                .setContent(R.id.view2));
        tabHost.addTab(tabHost.newTabSpec("tab3")
                .setIndicator("tab3",res.getDrawable(R.drawable.ic_tab_artists))
                .setContent(R.id.view3));
       tabHost.setCurrentTab(1);
       }
}

       在HelloWidget類內,創建了三個標籤,併爲每個標籤內容引用了三個不同的視圖id,當切換標籤時,他們引用的視圖將出現在標籤項的下方。這一點可以從main.xml佈局文件裏看的出來。同時,我們還爲三個標籤設置了相同的小圖標,用來凸顯標籤當前是否被選中。


         作爲演示,該類內只重寫了onCreate方法。該方法內的主要工作包括如下方面:


        1. 獲取用來持有標籤項的宿主(TabHost),因爲接下來的操作都是通過宿主來完成的;

        2. 創建標籤項(TabHost.TabSpec );

        3. 爲每個標籤項設置屬性,主要包括:

            3.1 設置標記;

            3.2 指定用於在標籤上顯示的圖標和文本;

            3.3 爲每個標籤設置內容,當該標籤被選中時將會打開內容所指定的活動;

        4. 將創建的標籤加入到宿主內;

        5. 設置默認被選中的標籤索引;


         運行後的結果如下圖:


       



3.  實現TabHost.TabContentFactory接口


     TabHost類的內部接口TabContentFactory只擁有一個成員函數createTabContent(String tag),它是用來創建標籤內容的回調函數。因此,實現TabContentFactory接口時需要實現createTabContent方法。


       現在,修改HelloWidget類,讓它實現TabHost.TabContentFactory接口,並實現createTabContent方法。修改後的內容如下:


 

@SuppressWarnings("deprecation")
public class HelloTabWidget extends TabActivity implements TabHost.TabContentFactory {
	   @Override
	    protected void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);

	        final TabHost tabHost = getTabHost();
	        Resources res = getResources();
	        tabHost.addTab(tabHost.newTabSpec("tab1")
	                .setIndicator("tab1", res.getDrawable(R.drawable.ic_tab_artists))
	                .setContent(this));
	        tabHost.addTab(tabHost.newTabSpec("tab2")
	                .setIndicator("tab2", res.getDrawable(R.drawable.ic_tab_artists))
	                .setContent(this));
	        tabHost.addTab(tabHost.newTabSpec("tab3")
	                .setIndicator("tab3", res.getDrawable(R.drawable.ic_tab_artists))
	                .setContent(this));
	    }

	    /** {@inheritDoc} */
	    public View createTabContent(String tag) {
	        final TextView tv = new TextView(this);
	        tv.setText("I am " + tag);
	        return tv;
	    }
}

       在新代碼裏需要注意以下幾個方面:


                1.  代碼中沒有使用res/layout/下的佈局文件;

                2.  爲標籤設置內容的方法使用的參數是"this",因爲HelloWidget實現了TabHost.TabContentFactory;

                3.  createTabContent方法來自於TabHost.TabContentFactory接口,此方法返回一個View,恰是標籤的內容;


       最後,運行程序的結果如下:



      



4.  把意圖設置爲標籤內容


        

        首先,修改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>

 

      

       爲創建一個標籤式佈局,我們需要一個TabHostTabWidgetTabHost則必須是佈局的根節點,該佈局包括了一個用於顯示標籤的TabWidget和一個用於顯示標籤所承載內容的FrameLayoutFrameLayout 是每個標籤內容顯示的地方,現在是空的,因爲TabHost會自動地把每個Activity嵌入其內。
       注意, TabWidgetFrameLayout 屬性分別引用"@android:id/tabs"和"@android:id/tabcontent"作爲他們的id。這兩個平臺內建組件id是爲標籤和標籤內容專門準備的,目的是爲了TabHost在需要時可以通過確切名字來取出TabWidgetFrameLayout,因此 ,這裏必須這樣寫。

        同時,把LinearLayout屬性裏的orientation設置爲“vertical”是爲了將標籤和其承載的內容“上下”排列。如果將orientation設置爲“horizontal”,當切換標籤時並不會看到它們所承載的內容。


       接下來,  在工程裏創建三個獨立的Activity類, 分別是ArtistsActivity, AlbumsActivity和SongsActivity。這些類分別代表了不同的三個標籤。每個類的實現都很簡單,只是顯示一個簡單的信息。例如:


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);
    }
}

        

       當切換到該類所代表的標籤時,則顯示“This is the Artists tab”。還有,不要忘記將這三個類加入到清單文件裏。


      接着,修改HelloWidget類,修改後如下:


@SuppressWarnings("deprecation")
public class HelloTabWidget extends TabActivity  {
    /** Called when the activity is first created. */
    @Override
    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_artists))
    	                  .setContent(intent);
    	    tabHost.addTab(spec);

    	    intent = new Intent().setClass(this, SongsActivity.class);
    	    spec = tabHost.newTabSpec("songs").setIndicator("Songs",
    	                      res.getDrawable(R.drawable.ic_tab_artists))
    	                  .setContent(intent);
    	    tabHost.addTab(spec);

    	    tabHost.setCurrentTab(2);
    }
}
 

        

       在經過修改後,我們創建三個intent,併爲每個intent關聯了一個活動, 然後把intent設置爲標籤的內容。當在切換標籤時,意圖內關聯的活動會被加載。值得注意的是,代碼裏可以不使用main.xml佈局文件,程序的運行結果也不會有所差異。

        

       最後,  運行的結果如下:


         

 

        

        好了,在基於API 4(或以前)的平臺版本上創建簡單標籤式佈局的方法就介紹到這裏。

 

                                                                                                                                                         2012年4月30日 晚畢。

        

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章