天天看點

Android :ListView詳解

在android開發中ListView是比較常用的元件,它以清單的形式展示具體内容,并且能夠根據資料的長度自适應顯示。抽空把對ListView的使用做了整理,并寫了個小例子,如下圖。

Android :ListView詳解

 清單的顯示需要三個元素:

1.ListVeiw 用來展示清單的View。

2.擴充卡 用來把資料映射到ListView上的中介。

3.資料    具體的将被映射的字元串,圖檔,或者基本元件。

根據清單的擴充卡類型,清單分為三種,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter

其中以ArrayAdapter最為簡單,隻能展示一行字。SimpleAdapter有最好的擴充性,可以自定義出各種效果。SimpleCursorAdapter可以認為是SimpleAdapter對資料庫的簡單結合,可以方面的把資料庫的内容以清單的形式展示出來。

 我們從最簡單的ListView開始:

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

public

class

MyListView

extends

Activity {

private

ListView listView;

//private List<String> data = new ArrayList<String>();

@Override

public

void

onCreate(Bundle savedInstanceState){

super

.onCreate(savedInstanceState);

listView =

new

ListView(

this

);

listView.setAdapter(

new

ArrayAdapter<String>(

this

, android.R.layout.simple_expandable_list_item_1,getData()));

setContentView(listView);

}

private

List<String> getData(){

List<String> data =

new

ArrayList<String>();

data.add(

"測試資料1"

);

data.add(

"測試資料2"

);

data.add(

"測試資料3"

);

data.add(

"測試資料4"

);

return

data;

}

}

上面代碼使用了ArrayAdapter(Context context, int textViewResourceId, List<T> objects)來裝配資料,要裝配這些資料就需要一個連接配接ListView視圖對象和數組資料的擴充卡來兩者的适配工作,ArrayAdapter的構造需要三個參數,依次為this,布局檔案(注意這裡的布局檔案描述的是清單的每一行的布局,android.R.layout.simple_list_item_1是系統定義好的布局檔案隻顯示一行文字,資料源(一個List集合)。同時用setAdapter()完成适配的最後工作。運作後的現實結構如下圖:

Android :ListView詳解

SimpleCursorAdapter

  sdk的解釋是這樣的:An easy adapter to map columns from a cursor to TextViews or ImageViews defined in an XML file. You can specify which columns you want, which views you want to display the columns, and the XML file that defines the appearance of these views。簡單的說就是友善把從遊标得到的資料進行清單顯示,并可以把指定的列映射到對應的TextView中。

  下面的程式是從電話簿中把聯系人顯示到類表中。先在通訊錄中添加一個聯系人作為資料庫的資料。然後獲得一個指向資料庫的Cursor并且定義一個布局檔案(當然也可以使用系統自帶的)。

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

public

class

MyListView2

extends

Activity {

private

ListView listView;

//private List<String> data = new ArrayList<String>();

@Override

public

void

onCreate(Bundle savedInstanceState){

super

.onCreate(savedInstanceState);

listView =

new

ListView(

this

);

Cursor cursor = getContentResolver().query(People.CONTENT_URI,

null

,

null

,

null

,

null

);

startManagingCursor(cursor);

ListAdapter listAdapter =

new

SimpleCursorAdapter(

this

, android.R.layout.simple_expandable_list_item_1,

cursor,

new

String[]{People.NAME},

new

int

[]{android.R.id.text1});

listView.setAdapter(listAdapter);

setContentView(listView);

}

}

 Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);先獲得一個指向系統通訊錄資料庫的Cursor對象獲得資料來源。

 startManagingCursor(cursor);我們将獲得的Cursor對象交由Activity管理,這樣Cursor的生命周期和Activity便能夠自動同步,省去自己手動管理Cursor。

 SimpleCursorAdapter 構造函數前面3個參數和ArrayAdapter是一樣的,最後兩個參數:一個包含資料庫的列的String型數組,一個包含布局檔案中對應元件id的int型數組。其作用是自動的将String型數組所表示的每一列資料映射到布局檔案對應id的元件上。上面的代碼,将NAME列的資料一次映射到布局檔案的id為text1的元件上。

注意:需要在AndroidManifest.xml中如權限:<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

運作後效果如下圖:

Android :ListView詳解

SimpleAdapter

simpleAdapter的擴充性最好,可以定義各種各樣的布局出來,可以放上ImageView(圖檔),還可以放上Button(按鈕),CheckBox(複選框)等等。下面的代碼都直接繼承了ListActivity,ListActivity和普通的Activity沒有太大的差别,不同就是對顯示ListView做了許多優化,方面顯示而已。

下面的程式是實作一個帶有圖檔的類表。

首先需要定義好一個用來顯示每一個列内容的xml

vlist.xml

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

<?

xml

version="1.0" encoding="utf-8"?>

<

LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="horizontal" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<

ImageView

android:id="@+id/img"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="5px"/>

<

LinearLayout

android:orientation="vertical"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<

TextView

android:id="@+id/title"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#FFFFFFFF"

android:textSize="22px" />

<

TextView

android:id="@+id/info"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#FFFFFFFF"

android:textSize="13px" />

</

LinearLayout

>

</

LinearLayout

>

下面是實作代碼:

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

public

class

MyListView3

extends

ListActivity {

// private List<String> data = new ArrayList<String>();

@Override

public

void

onCreate(Bundle savedInstanceState) {

super

.onCreate(savedInstanceState);

SimpleAdapter adapter =

new

SimpleAdapter(

this

,getData(),R.layout.vlist,

new

String[]{

"title"

,

"info"

,

"img"

},

new

int

[]{R.id.title,R.id.info,R.id.img});

setListAdapter(adapter);

}

private

List<Map<String, Object>> getData() {

List<Map<String, Object>> list =

new

ArrayList<Map<String, Object>>();

Map<String, Object> map =

new

HashMap<String, Object>();

map.put(

"title"

,

"G1"

);

map.put(

"info"

,

"google 1"

);

map.put(

"img"

, R.drawable.i1);

list.add(map);

map =

new

HashMap<String, Object>();

map.put(

"title"

,

"G2"

);

map.put(

"info"

,

"google 2"

);

map.put(

"img"

, R.drawable.i2);

list.add(map);

map =

new

HashMap<String, Object>();

map.put(

"title"

,

"G3"

);

map.put(

"info"

,

"google 3"

);

map.put(

"img"

, R.drawable.i3);

list.add(map);

return

list;

}

}

使用simpleAdapter的資料用一般都是HashMap構成的List,list的每一節對應ListView的每一行。HashMap的每個鍵值資料映射到布局檔案中對應id的元件上。因為系統沒有對應的布局檔案可用,我們可以自己定義一個布局vlist.xml。下面做适配,new一個SimpleAdapter參數一次是:this,布局檔案(vlist.xml),HashMap的 title 和 info,img。布局檔案的元件id,title,info,img。布局檔案的各元件分别映射到HashMap的各元素上,完成适配。

運作效果如下圖:

Android :ListView詳解

有按鈕的ListView

但是有時候,清單不光會用來做顯示用,我們同樣可以在在上面添加按鈕。添加按鈕首先要寫一個有按鈕的xml檔案,然後自然會想到用上面的方法定義一個擴充卡,然後将資料映射到布局檔案上。但是事實并非這樣,因為按鈕是無法映射的,即使你成功的用布局檔案顯示出了按鈕也無法添加按鈕的響應,這時就要研究一下ListView是如何現實的了,而且必須要重寫一個類繼承BaseAdapter。下面的示例将顯示一個按鈕和一個圖檔,兩行字如果單擊按鈕将删除此按鈕的所在行。并告訴你ListView究竟是如何工作的。效果如下:

Android :ListView詳解

vlist2.xml

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

<?

xml

version="1.0" encoding="utf-8"?>

<

LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="horizontal"

android:layout_width="fill_parent"

android:layout_height="fill_parent">

<

ImageView

android:id="@+id/img"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="5px"/>

<

LinearLayout

android:orientation="vertical"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<

TextView

android:id="@+id/title"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#FFFFFFFF"

android:textSize="22px" />

<

TextView

android:id="@+id/info"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:textColor="#FFFFFFFF"

android:textSize="13px" />

</

LinearLayout

>

<

Button

android:id="@+id/view_btn"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/s_view_btn"

android:layout_gravity="bottom|right" />

</

LinearLayout

>

程式代碼:

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

public

class

MyListView4

extends

ListActivity {

private

List<Map<String, Object>> mData;

@Override

public

void

onCreate(Bundle savedInstanceState) {

super

.onCreate(savedInstanceState);

mData = getData();

MyAdapter adapter =

new

MyAdapter(

this

);

setListAdapter(adapter);

}

private

List<Map<String, Object>> getData() {

List<Map<String, Object>> list =

new

ArrayList<Map<String, Object>>();

Map<String, Object> map =

new

HashMap<String, Object>();

map.put(

"title"

,

"G1"

);

map.put(

"info"

,

"google 1"

);

map.put(

"img"

, R.drawable.i1);

list.add(map);

map =

new

HashMap<String, Object>();

map.put(

"title"

,

"G2"

);

map.put(

"info"

,

"google 2"

);

map.put(

"img"

, R.drawable.i2);

list.add(map);

map =

new

HashMap<String, Object>();

map.put(

"title"

,

"G3"

);

map.put(

"info"

,

"google 3"

);

map.put(

"img"

, R.drawable.i3);

list.add(map);

return

list;

}

// ListView 中某項被選中後的邏輯

@Override

protected

void

onListItemClick(ListView l, View v,

int

position,

long

id) {

Log.v(

"MyListView4-click"

, (String)mData.get(position).get(

"title"

));

}

public

void

showInfo(){

new

AlertDialog.Builder(

this

)

.setTitle(

"我的listview"

)

.setMessage(

"介紹..."

)

.setPositiveButton(

"确定"

,

new

DialogInterface.OnClickListener() {

@Override

public

void

onClick(DialogInterface dialog,

int

which) {

}

})

.show();

}

public

final

class

ViewHolder{

public

ImageView img;

public

TextView title;

public

TextView info;

public

Button viewBtn;

}

public

class

MyAdapter

extends

BaseAdapter{

private

LayoutInflater mInflater;

public

MyAdapter(Context context){

this

.mInflater = LayoutInflater.from(context);

}

@Override

public

int

getCount() {

// TODO Auto-generated method stub

return

mData.size();

}

@Override

public

Object getItem(

int

arg0) {

// TODO Auto-generated method stub

return

null

;

}

@Override

public

long

getItemId(

int

arg0) {

// TODO Auto-generated method stub

return

;

}

@Override

public

View getView(

int

position, View convertView, ViewGroup parent) {

ViewHolder holder =

null

;

if

(convertView ==

null

) {

holder=

new

ViewHolder(); 

convertView = mInflater.inflate(R.layout.vlist2,

null

);

holder.img = (ImageView)convertView.findViewById(R.id.img);

holder.title = (TextView)convertView.findViewById(R.id.title);

holder.info = (TextView)convertView.findViewById(R.id.info);

holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);

convertView.setTag(holder);

}

else

{

holder = (ViewHolder)convertView.getTag();

}

holder.img.setBackgroundResource((Integer)mData.get(position).get(

"img"

));

holder.title.setText((String)mData.get(position).get(

"title"

));

holder.info.setText((String)mData.get(position).get(

"info"

));

holder.viewBtn.setOnClickListener(

new

View.OnClickListener() {

@Override

public

void

onClick(View v) {

showInfo();                

}

});

return

convertView;

}

}

}

  下面将對上述代碼,做詳細的解釋,listView在開始繪制的時候,系統首先調用getCount()函數,根據他的傳回值得到listView的長度(這也是為什麼在開始的第一張圖特别的标出清單長度),然後根據這個長度,調用getView()逐一繪制每一行。如果你的getCount()傳回值是0的話,清單将不顯示同樣return 1,就隻顯示一行。

  系統顯示清單時,首先執行個體化一個擴充卡(這裡将執行個體化自定義的擴充卡)。當手動完成适配時,必須手動映射資料,這需要重寫getView()方法。系統在繪制清單的每一行的時候将調用此方法。getView()有三個參數,position表示将顯示的是第幾行,covertView是從布局檔案中inflate來的布局。我們用LayoutInflater的方法将定義好的vlist2.xml檔案提取成View執行個體用來顯示。然後将xml檔案中的各個元件執行個體化(簡單的findViewById()方法)。這樣便可以将資料對應到各個元件上了。但是按鈕為了響應點選事件,需要為它添加點選監聽器,這樣就能捕獲點選事件。至此一個自定義的listView就完成了,現在讓我們回過頭從新審視這個過程。系統要繪制ListView了,他首先獲得要繪制的這個清單的長度,然後開始繪制第一行,怎麼繪制呢?調用getView()函數。在這個函數裡面首先獲得一個View(實際上是一個ViewGroup),然後再執行個體并設定各個元件,顯示之。好了,繪制完這一行了。那 再繪制下一行,直到繪完為止。在實際的運作過程中會發現listView的每一行沒有焦點了,這是因為Button搶奪了listView的焦點,隻要布局檔案中将Button設定為沒有焦點就OK了。

運作效果如下圖:

Android :ListView詳解

源碼下載下傳

繼續閱讀