
列表的顯示需要三個(gè)元素:
1.ListVeiw 用來(lái)展示列表的View。
2.適配器 用來(lái)把數據映射到ListView上的中介。
3.數據 具體的將被映射的字符串,圖片,或者基本組件。
根據列表的適配器類(lèi)型,列表分為三種,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter
其中以ArrayAdapter最為簡(jiǎn)單,只能展示一行字。SimpleAdapter有最好的擴充性,可以自定義出各種效果。SimpleCursorAdapter可以認為是SimpleAdapter對數據庫的簡(jiǎn)單結合,可以方面的把數據庫的內容以列表的形式展示出來(lái)。
我們從最簡(jiǎn)單的ListView開(kāi)始:
/*** @author allin**/public class MyListView extends Activity {private ListView listView;//private List<String> data = new ArrayList<String>();@Overridepublic 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)來(lái)裝配數據,要裝配這些數據就需要一個(gè)連接ListView視圖對象和數組數據的適配器來(lái)兩者的適配工作,ArrayAdapter的構造需要三個(gè)參數,依次為this,布局文件(注意這里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系統定義好的布局文件只顯示一行文字,數據源(一個(gè)List集合)。同時(shí)用setAdapter()完成適配的最后工作。運行后的現實(shí)結構如下圖:

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。簡(jiǎn)單的說(shuō)就是方便把從游標得到的數據進(jìn)行列表顯示,并可以把指定的列映射到對應的TextView中。
下面的程序是從電話(huà)簿中把聯(lián)系人顯示到類(lèi)表中。先在通訊錄中添加一個(gè)聯(lián)系人作為數據庫的數據。然后獲得一個(gè)指向數據庫的Cursor并且定義一個(gè)布局文件(當然也可以使用系統自帶的)。
/*** @author allin**/public class MyListView2 extends Activity {private ListView listView;//private List<String> data = new ArrayList<String>();@Overridepublic 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);先獲得一個(gè)指向系統通訊錄數據庫的Cursor對象獲得數據來(lái)源。
startManagingCursor(cursor);我們將獲得的Cursor對象交由Activity管理,這樣Cursor的生命周期和Activity便能夠自動(dòng)同步,省去自己手動(dòng)管理Cursor。
SimpleCursorAdapter 構造函數前面3個(gè)參數和ArrayAdapter是一樣的,最后兩個(gè)參數:一個(gè)包含數據庫的列的String型數組,一個(gè)包含布局文件中對應組件id的int型數組。其作用是自動(dòng)的將String型數組所表示的每一列數據映射到布局文件對應id的組件上。上面的代碼,將NAME列的數據一次映射到布局文件的id為text1的組件上。
注意:需要在A(yíng)ndroidManifest.xml中如權限:<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
運行后效果如下圖:

SimpleAdapter
simpleAdapter的擴展性最好,可以定義各種各樣的布局出來(lái),可以放上ImageView(圖片),還可以放上Button(按鈕),CheckBox(復選框)等等。下面的代碼都直接繼承了ListActivity,ListActivity和普通的Activity沒(méi)有太大的差別,不同就是對顯示ListView做了許多優(yōu)化,方面顯示而已。
下面的程序是實(shí)現一個(gè)帶有圖片的類(lèi)表。
首先需要定義好一個(gè)用來(lái)顯示每一個(gè)列內容的xml
vlist.xml
<?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>
下面是實(shí)現代碼:
/*** @author allin**/public class MyListView3 extends ListActivity {// private List<String> data = new ArrayList<String>();@Overridepublic 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的每個(gè)鍵值數據映射到布局文件中對應id的組件上。因為系統沒(méi)有對應的布局文件可用,我們可以自己定義一個(gè)布局vlist.xml。下面做適配,new一個(gè)SimpleAdapter參數一次是:this,布局文件(vlist.xml),HashMap的 title 和 info,img。布局文件的組件id,title,info,img。布局文件的各組件分別映射到HashMap的各元素上,完成適配。
運行效果如下圖:

有按鈕的ListView
但是有時(shí)候,列表不光會(huì )用來(lái)做顯示用,我們同樣可以在在上面添加按鈕。添加按鈕首先要寫(xiě)一個(gè)有按鈕的xml文件,然后自然會(huì )想到用上面的方法定義一個(gè)適配器,然后將數據映射到布局文件上。但是事實(shí)并非這樣,因為按鈕是無(wú)法映射的,即使你成功的用布局文件顯示出了按鈕也無(wú)法添加按鈕的響應,這時(shí)就要研究一下ListView是如何現實(shí)的了,而且必須要重寫(xiě)一個(gè)類(lèi)繼承BaseAdapter。下面的示例將顯示一個(gè)按鈕和一個(gè)圖片,兩行字如果單擊按鈕將刪除此按鈕的所在行。并告訴你ListView究竟是如何工作的。效果如下:

vlist2.xml
<?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>
程序代碼:
/*** @author allin**/public class MyListView4 extends ListActivity {private List<Map<String, Object>> mData;@Overridepublic 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 中某項被選中后的邏輯@Overrideprotected void onListItemClick(ListView l, View v, int position, long id) {Log.v("MyListView4-click", (String)mData.get(position).get("title"));}/*** listview中點(diǎn)擊按鍵彈出對話(huà)框*/public void showInfo(){new AlertDialog.Builder(this).setTitle("我的listview").setMessage("介紹...").setPositiveButton("確定", new DialogInterface.OnClickListener() {@Overridepublic 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);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn mData.size();}@Overridepublic Object getItem(int arg0) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int arg0) {// TODO Auto-generated method stubreturn 0;}@Overridepublic 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() {@Overridepublic void onClick(View v) {showInfo();}});return convertView;}}}
下面將對上述代碼,做詳細的解釋?zhuān)琹istView在開(kāi)始繪制的時(shí)候,系統首先調用getCount()函數,根據他的返回值得到listView的長(cháng)度(這也是為什么在開(kāi)始的第一張圖特別的標出列表長(cháng)度),然后根據這個(gè)長(cháng)度,調用getView()逐一繪制每一行。如果你的getCount()返回值是0的話(huà),列表將不顯示同樣return 1,就只顯示一行。
系統顯示列表時(shí),首先實(shí)例化一個(gè)適配器(這里將實(shí)例化自定義的適配器)。當手動(dòng)完成適配時(shí),必須手動(dòng)映射數據,這需要重寫(xiě)getView()方法。系統在繪制列表的每一行的時(shí)候將調用此方法。getView()有三個(gè)參數,position表示將顯示的是第幾行,covertView是從布局文件中inflate來(lái)的布局。我們用LayoutInflater的方法將定義好的vlist2.xml文件提取成View實(shí)例用來(lái)顯示。然后將xml文件中的各個(gè)組件實(shí)例化(簡(jiǎn)單的findViewById()方法)。這樣便可以將數據對應到各個(gè)組件上了。但是按鈕為了響應點(diǎn)擊事件,需要為它添加點(diǎn)擊監聽(tīng)器,這樣就能捕獲點(diǎn)擊事件。至此一個(gè)自定義的listView就完成了,現在讓我們回過(guò)頭從新審視這個(gè)過(guò)程。系統要繪制ListView了,他首先獲得要繪制的這個(gè)列表的長(cháng)度,然后開(kāi)始繪制第一行,怎么繪制呢?調用getView()函數。在這個(gè)函數里面首先獲得一個(gè)View(實(shí)際上是一個(gè)ViewGroup),然后再實(shí)例并設置各個(gè)組件,顯示之。好了,繪制完這一行了。那再繪制下一行,直到繪完為止。在實(shí)際的運行過(guò)程中會(huì )發(fā)現listView的每一行沒(méi)有焦點(diǎn)了,這是因為Button搶奪了listView的焦點(diǎn),只要布局文件中將Button設置為沒(méi)有焦點(diǎn)就OK了。
運行效果如下圖:

聯(lián)系客服