Android 開發之旅:view的幾種佈局方式及實踐

引言

通過前面兩篇:

  1. Android 開發之旅:又見Hello World!
  2. Android 開發之旅:深入分析佈局文件&又是“Hello World!”

我們對Android應用程序運行原理及佈局文件可謂有了比較深刻的認識和理解,並且用“Hello World!”程序來實踐證明了。在繼續深入Android開發之旅之前,有必要解決前兩篇中沒有介紹的遺留問題:View的幾種佈局顯示方法,以後就不會在針對佈局方面做過多的介紹。View的佈局顯示方式有下面幾種:線性佈局(Linear Layout)、相對佈局(Relative Layout)、表格佈局(Table Layout)、網格視圖(Grid View)、標籤佈局(Tab Layout)、列表視圖(List View)、絕對佈局(AbsoluteLayout)。本文雖然是介紹View的佈局方式,但不僅僅是這樣,其中涉及了很多小的知識點,絕對能給你帶來Android大餐!

本文的主要內容就是分別介紹以上視圖的七種佈局顯示方式效果及實現,大綱如下:

  1. 1、View佈局概述
  2. 2、線性佈局(Linear Layout)
    1. 2.1、Tips:android:layout_weight="1"
  3. 3、相對佈局(Relative Layout)
  4. 4、表格佈局(Table Layout)
  5. 5、列表視圖(List View)
    1. 5.1、一個小的改進
    2. 5.2、補充說明
  6. 6、網格視圖(Grid View)
  7. 7 、絕對佈局()
  8. 8、標籤佈局(Tab Layout)

1、view的佈局顯示概述

通過前面的學習我們知道:在一個Android應用程序中,用戶界面通過ViewViewGroup對象構建。Android中有很多種View和ViewGroup,他們都繼承自View類。View對象是Android平臺上表示用戶界面的基本單元。

View的佈局顯示方式直接影響用戶界面,View的佈局方式是指一組View元素如何佈局,準確的說是一個ViewGroup中包含的一些View怎麼樣佈局。ViewGroup類是佈局(layout)和視圖容器(View container)的基類,此類也定義了ViewGroup.LayoutParams類,它作爲佈局參數的基類,此類告訴父視圖其中的子視圖想如何顯示。例如,XML佈局文件中名爲layout_something的屬性(參加上篇的4.2節)。我們要介紹的View的佈局方式的類,都是直接或間接繼承自ViewGroup類,如下圖所示:

Android 開發之旅:view的幾種佈局方式及實踐

圖1、繼承自ViewGroup的一些佈局類

其實,所有的佈局方式都可以歸類爲ViewGroup的5個類別,即ViewGroup的5個直接子類。其它的一些佈局都擴展自這5個類。下面分小節分別介紹View的七種佈局顯示方式。

2、線性佈局(Linear Layout)

線性佈局:是一個ViewGroup以線性方向顯示它的子視圖(view)元素,即垂直地水平地。之前我們的Hello World!程序中view的佈局方式就是線性佈局的,一定不陌生!如下所示res/layour/main.xml

  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  3.               android:layout_width="fill_parent"   
  4.               android:layout_height="fill_parent"   
  5.               android:orientation="horizontal"><!-- have an eye on ! -->   
  6.     <Button android:id="@+id/button1"   
  7.             android:layout_width="wrap_content"   
  8.             android:layout_height="wrap_content"              
  9.             android:text="Hello, I am a Button1"   
  10.             android:layout_weight="1"   
  11.             />   
  12.     <Button android:id="@+id/button2"   
  13.     android:layout_width="wrap_content"   
  14.     android:layout_height="wrap_content"   
  15.     android:text="Hello, I am a Button2"   
  16.     android:layout_weight="1"   
  17.     />   
  18.     <Button android:id="@+id/button3"   
  19.     android:layout_width="wrap_content"   
  20.     android:layout_height="wrap_content"   
  21.     android:text="Hello, I am a Button3"   
  22.     android:layout_weight="1"   
  23.     />   
  24.     <Button android:id="@+id/button4"   
  25.     android:layout_width="wrap_content"   
  26.     android:layout_height="wrap_content"   
  27.     android:text="Hello, I am a Button4"   
  28.     android:layout_weight="1"   
  29.     />   
  30.     <Button android:id="@+id/button5"   
  31.     android:layout_width="wrap_content"   
  32.     android:layout_height="wrap_content"   
  33.     android:text="Hello, I am a Button5"   
  34.     android:layout_weight="1"   
  35.     />   
  36. </LinearLayout>  

從上面可以看出根LinearLayout視圖組(ViewGroup)包含5個Button,它的子元素是以線性方式(horizontal,水平的)佈局,運行效果如下圖所示:

Android 開發之旅:view的幾種佈局方式及實踐

圖2、線性佈局(水平或者說是橫向)

 如果你在android:orientation="horizontal"設置爲vertical,則是是垂直或者說是縱向的,如下圖所示:

Android 開發之旅:view的幾種佈局方式及實踐

圖3、線性佈局(垂直或者說是縱向)

2.1、Tips:android:layout_weight="1"

這個屬性很關鍵,如果你沒有顯示設置它,它默認爲0。把上面佈局文件(水平顯示的那個)中的這個屬性都去掉,運行會得出如下結果:

Android 開發之旅:view的幾種佈局方式及實踐

圖4、layout_weight屬性

沒有了這個屬性,我們本來定義的5個Button運行後卻只顯示了2個Button,爲什麼呢??

"weight"顧名思義是權重的意思,layout_weight 用於給一個線性佈局中的諸多視圖的重要程度賦值。所有的視圖都有一個layout_weight值,默認爲零,意思是需要顯示多大的視圖就佔據多大的屏幕空間。這就不難解釋爲什麼會造成上面的情況了:Button1~Button5都設置了layout_height和layout_width屬性爲wrap_content即包住文字內容,他們都沒有設置layout_weight 屬性,即默認爲0.,這樣Button1和Button2根據需要的內容佔據了整個屏幕,別的就顯示不了啦!

若賦一個高於零的值,則將父視圖中的可用空間分割,分割大小具體取決於每一個視圖的layout_weight值以及該值在當前屏幕布局的整體layout_weight值和在其它視圖屏幕布局的layout_weight值中所佔的比率而定。舉個例子:比如說我們在 水平方向上有一個文本標籤和兩個文本編輯元素。該文本標籤並無指定layout_weight值,所以它將佔據需要提供的最少空間。如果兩個文本編輯元素每一個的layout_weight值都設置爲1,則兩者平分在父視圖佈局剩餘的寬度(因爲我們聲明這兩者的重要度相等)。如果兩個文本編輯元素其中第一個的layout_weight值設置爲1,而第二個的設置爲2,則剩餘空間的三分之二分給第一個,三分之一分給第二個(數值越小,重要度越高)。 

3、相對佈局(Relative Layout)

相對佈局:是一個ViewGroup以相對位置顯示它的子視圖(view)元素,一個視圖可以指定相對於它的兄弟視圖的位置(例如在給定視圖的左邊或者下面)或相對於RelativeLayout的特定區域的位置(例如底部對齊,或中間偏左)。

相對佈局是設計用戶界面的有力工具,因爲它消除了嵌套視圖組。如果你發現你使用了多個嵌套的LinearLayout視圖組後,你可以考慮使用一個RelativeLayout視圖組了。看下面的res/layour/main.xml

  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  3.     android:layout_width="fill_parent"   
  4.     android:layout_height="fill_parent">   
  5.     <TextView   
  6.         android:id="@+id/label"   
  7.         android:layout_width="fill_parent"   
  8.         android:layout_height="wrap_content"   
  9.         android:text="Type here:"/>   
  10.     <EditText   
  11.         android:id="@+id/entry"   
  12.         android:layout_width="fill_parent"   
  13.         android:layout_height="wrap_content"   
  14.         android:background="@android:drawable/editbox_background"   
  15.         android:layout_below="@id/label"/><!-- have an eye on ! -->   
  16.     <Button   
  17.         android:id="@+id/ok"   
  18.         android:layout_width="wrap_content"   
  19.         android:layout_height="wrap_content"   
  20.         android:layout_below="@id/entry"  <!-- have an eye on ! -->   
  21.        android:layout_alignParentRight="true" <!-- have an eye on ! -->   
  22.         android:layout_marginLeft="10dip"   
  23.         android:text="OK" />   
  24.     <Button   
  25.         android:layout_width="wrap_content"   
  26.         android:layout_height="wrap_content"   
  27.         android:layout_toLeftOf="@id/ok" <!-- have an eye on ! -->   
  28.         android:layout_alignTop="@id/ok" <!-- have an eye on ! -->   
  29.         android:text="Cancel" />   
  30. </RelativeLayout>  

從上面的佈局文件我們知道,RelativeLayout視圖組包含一個TextView、一個EditView、兩個Button,注意標記了<!-- have an eye on ! -->的屬性,在使用相對佈局方式中就是使用這些類似的屬性來定位視圖到你想要的位置,它們的值是你參照的視圖的id。這些屬性的意思很簡單,就是英文單詞的直譯,就不多做介紹了。運行之後,得如下結果:

Android 開發之旅:view的幾種佈局方式及實踐 

圖5、相對佈局

4、 表格佈局(Table Layout)

表格佈局:是一個ViewGroup以表格顯示它的子視圖(view)元素,即行和列標識一個視圖的位置。其實Android的表格佈局跟HTML中的表格佈局非常類似,TableRow 就像HTML表格的<tr>標記。

用表格佈局需要知道以下幾點

  1. android:shrinkColumns,對應的方法:setShrinkAllColumns(boolean),作用:設置表格的列是否收縮(列編號從0開始,下同),多列用逗號隔開(下同),如android:shrinkColumns="0,1,2",即表格的第1、2、3列的內容是收縮的以適合屏幕,不會擠出屏幕。
  2. android:collapseColumns,對應的方法:setColumnCollapsed(int,boolean),作用:設置表格的列是否隱藏
  3. android:stretchColumns,對應的方法:setStretchAllColumns(boolean),作用:設置表格的列是否拉伸

看下面的res/layour/main.xml

  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  3.               android:layout_width="fill_parent"   
  4.               android:layout_height="fill_parent"   
  5.               android:shrinkColumns="0,1,2"><!-- have an eye on ! -->   
  6.     <TableRow><!-- row1 -->   
  7.     <Button android:id="@+id/button1"   
  8.             android:layout_width="wrap_content"   
  9.             android:layout_height="wrap_content"              
  10.             android:text="Hello, I am a Button1"   
  11.             android:layout_column="0"   
  12.             />   
  13.        <Button android:id="@+id/button2"   
  14.      android:layout_width="wrap_content"   
  15.      android:layout_height="wrap_content"   
  16.      android:text="Hello, I am a Button2"   
  17.      android:layout_column="1"   
  18.      />   
  19.      </TableRow>   
  20.     <TableRow><!-- row2 -->   
  21.     <Button android:id="@+id/button3"   
  22.             android:layout_width="wrap_content"   
  23.             android:layout_height="wrap_content"              
  24.             android:text="Hello, I am a Button3"   
  25.             android:layout_column="1"   
  26.             />   
  27. <Button android:id="@+id/button4"   
  28.      android:layout_width="wrap_content"   
  29.      android:layout_height="wrap_content"   
  30.      android:text="Hello, I am a Button4"   
  31.      android:layout_column="1"   
  32.      />   
  33. </TableRow>   
  34. <TableRow>      
  35.      <Button android:id="@+id/button5"   
  36.      android:layout_width="wrap_content"   
  37.      android:layout_height="wrap_content"   
  38.      android:text="Hello, I am a Button5"   
  39.      android:layout_column="2"   
  40.      />   
  41. </TableRow>   
  42. </TableLayout>  

運行之後可以得出下面的結果:

Android 開發之旅:view的幾種佈局方式及實踐

圖6、表格佈局

5、列表視圖(List View)

列表佈局:是一個ViewGroup以列表顯示它的子視圖(view)元素,列表是可滾動的列表。列表元素通過ListAdapter自動插入到列表。

ListAdapter:擴展自Adapter,它是ListView和數據列表之間的橋樑。ListView可以顯示任何包裝在ListAdapter中的數據。該類提供兩個公有類型的抽象方法:

  1. public abstract boolean  areAllItemsEnabled () :表示ListAdapter中的所有元素是否可激活的?如果返回真,即所有的元素是可選擇的即可點擊的。
  2. public abstract boolean  isEnabled (int position) :判斷指定位置的元素是否可激活的?

下面通過一個例子來,創建一個可滾動的列表,並從一個字符串數組讀取列表元素。當一個元素被選擇時,顯示該元素在列表中的位置的消息。

1)、首先,將res/layour/main.xml的內容置爲如下:

  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <TextView xmlns:android="http://schemas.android.com/apk/res/android"   
  3.     android:layout_width="fill_parent"   
  4.     android:layout_height="fill_parent"   
  5.     android:padding="10dp"   
  6.     android:textSize="16sp" >   
  7. </TextView> 

這樣就定義了元素在列表中的佈局。

2)、src/skynet.com.cnblogs.www/HelloWorld.java文件的代碼如下:

  1. package skynet.com.cnblogs.www;  
  2.  
  3. import android.app.ListActivity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.widget.AdapterView;  
  7. import android.widget.ArrayAdapter;  
  8. import android.widget.ListView;  
  9. import android.widget.TextView;  
  10. import android.widget.Toast;  
  11. import android.widget.AdapterView.OnItemClickListener;  
  12.  
  13. public class HelloWorld extends ListActivity  {    //注意這裏Helloworld類不是擴展自Acitvity,而是擴展自ListAcitivty  
  14.     /** Called when the activity is first created. */ 
  15.     @Override 
  16.     public void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setListAdapter(new ArrayAdapter<String>(this, R.layout.main, COUNTRIES));  
  19.  
  20.         ListView lv = getListView();  
  21.         lv.setTextFilterEnabled(true);  
  22.  
  23.         lv.setOnItemClickListener(new OnItemClickListener() {  
  24.           public void onItemClick(AdapterView<?> parent, View view,  
  25.               int position, long id) {  
  26.             // When clicked, show a toast with the TextView text  
  27.             Toast.makeText(getApplicationContext(), ((TextView) view).getText(),  
  28.                 Toast.LENGTH_SHORT).show();  
  29.           }  
  30.         });  
  31.     }  
  32.     static final String[] COUNTRIES = new String[] {  
  33.         "1""2""3""4""5",  
  34.         "6""7""8""9""10",  
  35.         "11""12""13""14""15",  
  36.         "16""17""18""19""20",  
  37.         "21""22""23""24" 
  38.       };  

NoteonCreate()函數中並不像往常一樣通過setContentView()爲活動(Activity)加載佈局文件,替代的是通過setListAdapter(ListAdapter)自動添加一個ListView填充整個屏幕的ListActivity。在此文件中這個方法以一個ArrayAdapter爲參數:setListAdapter(new ArrayAdapter<String>(this, R.layout.main, COUNTRIES)),這個ArrayAdapter管理填入ListView中的列表元素。ArrayAdapter的構造函數的參數爲:this(表示應用程序的上下文context)、表示ListViewde佈局文件(這裏是R.layout.main)、插入ListView的List對象對數組(這裏是COUNTRES)。

setOnItemClickListener(OnItemClickListener)定義了每個元素的點擊(on-click)的監聽器,當ListView中的元素被點擊時,onItemClick()方法被調用,在這裏是即一個Toast消息——每個元素的位置將顯示。

3)、運行應用程序得如下結果(點擊1之後,在下面顯示了1):

Android 開發之旅:view的幾種佈局方式及實踐

圖7、列表佈局

NOTE:如果你改了HelloWorld extends ListActivity 而不是Activity之後,運行程序是提示:“Conversion to Dalvik format failed with error 1”。可以這麼解決:解決辦法是 Project > Clean... > Clean project selected below > Ok

5.1、一個小的改進

上面我們是把要填充到ListView中的元素硬編碼到HelloWorld.java文件中,這樣就缺乏靈活性!也不符合推薦的應用程序的界面控制它行爲的代碼更好地分離的準則!

其實我們可以把要填充到ListView的元素寫到res/values/strings.xml文件中的<string-array>元素中,然後再源碼中動態地讀取。這樣strings.xml的內容類似下面:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3.     <string-array name="countries_array"> 
  4.         <item>1</item> 
  5.         <item>2</item> 
  6.         <item>3</item> 
  7.         <item>4</item> 
  8.         <item>5</item> 
  9.         <item>6</item> 
  10.         <item>7</item> 
  11.     </string-array> 
  12. </resources> 

然而HelloWorld.java文件中的onCreate()函數,則這樣動態訪問這個數組及填充到ListVies:

String[] countries = getResources().getStringArray(R.array.countries_array);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, countries));

5.2、補充說明

首先總結一下列表佈局的關鍵部分:

  • 佈局文件中定義ListView
  • Adapter用來將數據填充到ListView
  • 要填充到ListView的數據,這些數據可以字符串、圖片、控件等等

其中Adapter是ListView和數據源之間的橋樑,根據數據源的不同Adapter可以分爲三類:

  • String[]: ArrayAdapter
  • List<Map<String,?>>: SimpleAdapter
  • 數據庫Cursor: SimpleCursorAdapter

使用ArrayAdapter(數組適配器)顧名思義,需要把數據放入一個數組以便顯示,上面的例子就是這樣的;SimpleAdapter能定義各種各樣的佈局出來,可以放上ImageView(圖片),還可以放上Button(按鈕),CheckBox(複選框)等等;SimpleCursorAdapter是和數據庫有關的東西。篇幅有限後面兩種就不舉例實踐了。你可以參考android ListView詳解orArrayAdapter ,SimpleAdapter ,SimpleCursorAdapter 區別

6、網格視圖(Grid View)

網格佈局:是一個ViewGroup以網格顯示它的子視圖(view)元素,即二維的、滾動的網格。網格元素通過ListAdapter自動插入到網格。ListAdapter跟上面的列表佈局是一樣的,這裏就不重複累述了。

下面也通過一個例子來,創建一個顯示圖片縮略圖的網格。當一個元素被選擇時,顯示該元素在列表中的位置的消息。

1)、首先,將上面實踐截取的圖片放入res/drawable/

2)、res/layour/main.xml的內容置爲如下:這個GridView填滿整個屏幕,而且它的屬性都很好理解,按英文單詞的意思就對了。

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <GridView xmlns:android="http://schemas.android.com/apk/res/android"   
  3.     android:id="@+id/gridview" 
  4.     android:layout_width="fill_parent"   
  5.     android:layout_height="fill_parent" 
  6.     android:columnWidth="90dp" 
  7.     android:numColumns="auto_fit" 
  8.     android:verticalSpacing="10dp" 
  9.     android:horizontalSpacing="10dp" 
  10.     android:stretchMode="columnWidth" 
  11.     android:gravity="center" 
  12. /> 

3)、然後,HelloWorld.java文件中onCreate()函數如下:

  1. public void onCreate(Bundle savedInstanceState) {  
  2.         super.onCreate(savedInstanceState);  
  3.         setContentView(R.layout.main);  
  4.  
  5.         GridView gridview = (GridView) findViewById(R.id.gridview);  
  6.         gridview.setAdapter(new ImageAdapter(this));  
  7.  
  8.         gridview.setOnItemClickListener(new OnItemClickListener() {  
  9.             public void onItemClick(AdapterView<?> parent, View v, int position, long id) {  
  10.                 Toast.makeText(HelloWorld.this" " + position, Toast.LENGTH_SHORT).show();  
  11.             }  
  12.         });  
  13.     }  

onCreate()函數跟通常一樣,首先調用超類的onCreate()函數函數,然後通過setContentView()爲活動(Activity)加載佈局文件。緊接着是,通過GridView的id獲取佈局文件中的gridview,然後調用它的setListAdapter(ListAdapter)函數填充它,它的參數是一個我們自定義的ImageAdapter。後面的工作跟列表佈局中一樣,爲監聽網格中的元素被點擊的事件而做的工作。

4)、實現我們自定義ImageAdapter,新添加一個類文件,它的代碼如下:

  1. package skynet.com.cnblogs.www;  
  2.  
  3. import android.content.Context;  
  4. import android.view.View;  
  5. import android.view.ViewGroup;  
  6. import android.widget.BaseAdapter;  
  7. import android.widget.GridView;  
  8. import android.widget.ImageView;  
  9.  
  10. public class ImageAdapter extends BaseAdapter {  
  11.     private Context mContext;  
  12.  
  13.     public ImageAdapter(Context c) {  
  14.         mContext = c;  
  15.     }  
  16.  
  17.     public int getCount() {  
  18.         return mThumbIds.length;  
  19.     }  
  20.  
  21.     public Object getItem(int position) {  
  22.         return null;  
  23.     }  
  24.  
  25.     public long getItemId(int position) {  
  26.         return 0;  
  27.     }  
  28.  
  29.     // create a new ImageView for each item referenced by the Adapter  
  30.     public View getView(int position, View convertView, ViewGroup parent) {  
  31.         ImageView p_w_picpathView;  
  32.         if (convertView == null) {  // if it's not recycled, initialize some attributes  
  33.             p_w_picpathView = new ImageView(mContext);  
  34.             p_w_picpathView.setLayoutParams(new GridView.LayoutParams(8585));  
  35.             p_w_picpathView.setScaleType(ImageView.ScaleType.CENTER_CROP);  
  36.             p_w_picpathView.setPadding(8888);  
  37.         } else {  
  38.             p_w_picpathView = (ImageView) convertView;  
  39.         }  
  40.  
  41.         p_w_picpathView.setImageResource(mThumbIds[position]);  
  42.         return p_w_picpathView;  
  43.     }  
  44.  
  45.     // references to our p_w_picpaths  
  46.     private Integer[] mThumbIds = {  
  47.             R.drawable.linearlayout1, R.drawable.linearlayout2,  
  48.             R.drawable.linearlayout3, R.drawable.listview,  
  49.             R.drawable.relativelayout, R.drawable.tablelayout  
  50.     };  

ImageAdapter類擴展自BaseAdapter,所以首先得實現它所要求必須實現的方法。構造函數和getcount()函數很好理解,而getItem(int)應該返回實際對象在適配器中的特定位置,但是這裏我們不需要。類似地,getItemId(int)應該返回元素的行號,但是這裏也不需要。

這裏重點要介紹的是getView()方法,它爲每個要添加到ImageAdapter的圖片都創建了一個新的View。當調用這個方法時,一個View是循環再用的,因此要確認對象是否爲空。如果是空的話,一個ImageView就被實例化且配置想要的顯示屬性:

  1. setLayoutParams(ViewGroup.LayoutParams):設置View的高度和寬度,這確保不管drawable中圖片的大小,每個圖片都被重新設置大小且剪裁以適應這些尺寸。
  2. setScaleType(ImageView.ScaleType):聲明圖片應該向中心剪裁(如果需要的話)。
  3. setPadding(int, int, int, int):定義補距,如果圖片有不同的橫縱比,小的補距將導致更多的剪裁以適合設置的ImageView的高度和寬度。

如果View傳到getView()不是空的,則本地的ImageView初始化時將循環再用View對象。在getView()方法末尾,position整數傳入setImageResource()方法以從mThumbIds數組中選擇圖片。

運行程序會得到如下結果(點擊第一張圖片之後):

Android 開發之旅:view的幾種佈局方式及實踐

圖8、網格佈局

7、絕對佈局(AbsoluteLayout)

絕對佈局:是一個ViewGroup以絕對方式顯示它的子視圖(view)元素,即以座標的方式來定位在屏幕上位置。

這種佈局方式很好理解,在佈局文件或編程地設置View的座標,從而絕對地定位。如下所示佈局文件:

  1. <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  2.    android:id="@+id/AbsoluteLayout01"   
  3.    android:layout_width="fill_parent"   
  4.    android:layout_height="fill_parent"   
  5.    > 
  6.    <TextView android:id="@+id/txtIntro" 
  7.      android:text="絕對佈局" 
  8.      android:layout_width="fill_parent" 
  9.      android:layout_height="wrap_content" 
  10.      android:layout_x="20dip"<!-- have an eye on ! --> 
  11.      android:layout_y="20dip"><!-- have an eye on ! --> 
  12.    </TextView> 
  13. </AbsoluteLayout> 

簡單吧,這裏不在深入了!

8、標籤佈局(Tab Layout)

標籤佈局:是一個ViewGroup以標籤的方式顯示它的子視圖(view)元素,就像在Firefox中的一個窗口中顯示多個網頁一樣。

爲了狂創建一個標籤UI(tabbed UI),需要使用到TabHostTabWidgetTabHost必須是佈局的根節點,它包含爲了顯示標籤的TabWidget和顯示標籤內容的FrameLayout

可以有兩種方式實現標籤內容:使用標籤在同一個活動中交換視圖、使用標籤在完全隔離的活動之間改變。根據你的需要,選擇不同的方式,但是如果每個標籤提供不同的用戶活動,爲每個標籤選擇隔離的活動,因此你可以更好地以分離的組管理應用程序,而不是一個巨大的應用程序和佈局。下面還有一個例子來創建一個標籤UI,每個標籤使用隔離的活動。

1)、在項目中建立三個隔離的Activity類:ArtistisActivity、AlbumActivity、SongActivity。它們每個表示一個分隔的標籤。每個通過TextView顯示簡單的一個消息,例如:

  1. public class ArtistsActivity extends Activity {  
  2.     public void onCreate(Bundle savedInstanceState) {  
  3.         super.onCreate(savedInstanceState);  
  4.  
  5.         TextView textview = new TextView(this);  
  6.         textview.setText("This is the Artists tab");  
  7.         setContentView(textview);  
  8.     }  

其它兩個類也類似。

2)、設置每個標籤的圖標,每個圖標應該有兩個版本:一個是選中時的,一個是未選中時的。通常的設計建議是,選中的圖標應該是深色(灰色),未選中的圖標是淺色(白色)。

現在創建一個state-list drawable指定哪個圖標表示標籤的狀態:將圖片放到res/drawable目錄下並創建一個新的XML文件命名爲ic_tab_artists.xml,內容如下:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android"> 
  3.     <!-- When selected, use grey --> 
  4.     <item android:drawable="@drawable/ic_tab_artists_grey" 
  5.           android:state_selected="true" /> 
  6.     <!-- When not selected, use white--> 
  7.     <item android:drawable="@drawable/ic_tab_artists_white" /> 
  8. </selector> 

3)、res/layour/main.xml的內容置爲如下:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:id="@android:id/tabhost" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent"> 
  6.     <LinearLayout 
  7.         android:orientation="vertical" 
  8.         android:layout_width="fill_parent" 
  9.         android:layout_height="fill_parent" 
  10.         android:padding="5dp"> 
  11.         <TabWidget 
  12.             android:id="@android:id/tabs" 
  13.             android:layout_width="fill_parent" 
  14.             android:layout_height="wrap_content" /> 
  15.         <FrameLayout 
  16.             android:id="@android:id/tabcontent" 
  17.             android:layout_width="fill_parent" 
  18.             android:layout_height="fill_parent" 
  19.             android:padding="5dp" /> 
  20.     </LinearLayout> 
  21. </TabHost> 

這個佈局將顯示標籤和提供上面創建的活動之間的導航。TabHost要求包含一個TabWidget和一個FrameLayoutTabWidgetFrameLayoutTabHost以線性垂直地顯示。

4)、HelloWorld.java文件源碼如下:

  1. package skynet.com.cnblogs.www;  
  2.  
  3. import android.widget.TabHost;  
  4. import android.app.TabActivity;  
  5. import android.content.Intent;  
  6. import android.content.res.Resources;  
  7. import android.os.Bundle;  
  8.  
  9. public class HelloWorld extends TabActivity{  
  10.     /** Called when the activity is first created. */ 
  11.     @Override 
  12.     public void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         setContentView(R.layout.main);  
  15.  
  16.         Resources res = getResources(); // Resource object to get Drawables  
  17.         TabHost tabHost = getTabHost();  // The activity TabHost  
  18.         TabHost.TabSpec spec;  // Resusable TabSpec for each tab  
  19.         Intent intent;  // Reusable Intent for each tab  
  20.  
  21.         // Create an Intent to launch an Activity for the tab (to be reused)  
  22.         intent = new Intent().setClass(this, ArtistsActivity.class);  
  23.  
  24.         // Initialize a TabSpec for each tab and add it to the TabHost  
  25.         spec = tabHost.newTabSpec("artists").setIndicator("Artists",  
  26.                           res.getDrawable(R.drawable.ic_tab_artists))  
  27.                       .setContent(intent);  
  28.         tabHost.addTab(spec);  
  29.  
  30.         // Do the same for the other tabs  
  31.         intent = new Intent().setClass(this, AlbumsActivity.class);  
  32.         spec = tabHost.newTabSpec("albums").setIndicator("Albums",  
  33.                           res.getDrawable(R.drawable.ic_tab_artists))  
  34.                       .setContent(intent);  
  35.         tabHost.addTab(spec);  
  36.  
  37.         intent = new Intent().setClass(this, SongsActivity.class);  
  38.         spec = tabHost.newTabSpec("songs").setIndicator("Songs",  
  39.                           res.getDrawable(R.drawable.ic_tab_artists))  
  40.                       .setContent(intent);  
  41.         tabHost.addTab(spec);  
  42.  
  43.         tabHost.setCurrentTab(2);  
  44.     }  

設置每個標籤的文字和圖標,並分配每個標籤一個活動(這裏爲了方便三個標籤都有相同的圖標)。TabHost的引用第一次通過getTabHost()獲取。然後,爲每個標籤,創建TabHost.TabSpec定義標籤的屬性。newTabSpec(String)方法創建一個新的TabHost.TabSpec以給定的字符串標識標籤。調用TabHost.TabSpec, setIndicator(CharSequence, Drawable)爲每個標籤設置文字和圖標,調用setContent(Intent)指定Intent去打開合適的活動。每個TabHost.TabSpec通過調用addTab(TabHost.TabSpec)添加到TabHost。

最後,setCurrentTab(int)設置打開默認顯示的標籤,通過索引標籤的位置。

5)、打開Android的清單文件AndroidManifest.xml,添加NoTitleBar主題到HelloWorld的<activity>標記。這將移除默認應用程序的標題和頂端佈局,給標籤騰出位置。<activity>標記應該像這樣:

  1. <activity android:name=".HelloWorld" 
  2.                   android:label="@string/app_name" 
  3.                   android:theme="@android:style/Theme.NoTitleBar"> 

你運行這個程序能夠得到什麼結果呢?請自行檢查。不過我在這裏告訴你很有可能會運行不了,報“java.lang.NullPointerException”錯!我想運行這個例子的很多人都會有這個問題,不信你試試!

PS:其實這也算是Android的一個bug,而且這個bug在2.2中還沒有解決,這個問題全球N多人都碰到了,並在http://code.google.com/p/android/issues中掛號了,相關問題的編號有不止一個。

 

接着往下看……

如果你看了我這篇文章,你一定會是個幸運兒!經過我艱苦的調試+找資料,我找到了解決方法:

在清單文件AndroidManifest.xml,添加下面三個Activity:

  1. <activity android:name=".AlbumsActivity"  android:label="@string/app_name"></activity>   
  2. <activity android:name=".ArtistsActivity" android:label="@string/app_name"></activity>   
  3. <activity android:name=".SongsActivity"  android:label="@string/app_name"></activity>  

現在運行可以看到如下結果:

Android 開發之旅:view的幾種佈局方式及實踐 

圖9、標籤佈局

 

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