android的listview問題

原文地址:android的listview問題     作者:Jaffer傑發


在android開發中ListView是比較常用的組件,它以列表的形式展示具體內容,並且能夠根據數據的長度自適應顯示。抽空把對ListView的使用做了整理,並寫了個小例子,如下圖。

[轉載]android的listview問題

列表的顯示需要三個元素:

1.ListVeiw 用來展示列表的View。

2.適配器 用來把數據映射到ListView上的中介。

3.數據 具體的將被映射的字符串,圖片,或者基本組件。

根據列表的適配器類型,列表分爲三種,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter

其中以ArrayAdapter最爲簡單,只能展示一行字。SimpleAdapter有最好的擴充性,可以自定義出各種效果。 SimpleCursorAdapter可以認爲是SimpleAdapter對數據庫的簡單結合,可以方面的把數據庫的內容以列表的形式展示出來。

我們從最簡單的ListView開始:


01 
05  publicclassMyListViewextendsActivity {
06 
07  privateListView listView;
08  //private List<String> data = new ArrayList<String>();
09  @Override
10  publicvoidonCreate(Bundle savedInstanceState){
11  super.onCreate(savedInstanceState);
12 
13  listView =newListView(this);
14  listView.setAdapter(newArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));
15  setContentView(listView);
16  }
17 
18 
19 
20  privateList<String> getData(){
21 
22  List<String> data =newArrayList<String>();
23  data.add("測試數據1");
24  data.add("測試數據2");
25  data.add("測試數據3");
26  data.add("測試數據4");
27 
28  returndata;
29  }
30  }

上面代碼使用了ArrayAdapter(Contextcontext, 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並且定義一個佈局文件(當然也可以使用系統自帶的)。


01 
05  publicclassMyListView2extendsActivity {
06 
07  privateListView listView;
08  //private List<String> data = new ArrayList<String>();
09  @Override
10  publicvoidonCreate(Bundle savedInstanceState){
11  super.onCreate(savedInstanceState);
12 
13  listView =newListView(this);
14 
15  Cursor cursor = getContentResolver().query(People.CONTENT_URI,null,null,null,null);
16  startManagingCursor(cursor);
17 
18  ListAdapter listAdapter =newSimpleCursorAdapter(this, android.R.layout.simple_expandable_list_item_1,
19  cursor,
20  newString[]{People.NAME},
21  newint[]{android.R.id.text1});
22 
23  listView.setAdapter(listAdapter);
24  setContentView(listView);
25  }
26 
27 
28  }

Cursorcursor = 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


01  <?xmlversion="1.0"encoding="utf-8"?>
02  <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
03  android:orientation="horizontal"android:layout_width="fill_parent"
04  android:layout_height="fill_parent">
05 
06 
07  <ImageViewandroid:id="@+id/img"
08  android:layout_width="wrap_content"
09  android:layout_height="wrap_content"
10  android:layout_margin="5px"/>
11 
12  <LinearLayoutandroid:orientation="vertical"
13  android:layout_width="wrap_content"
14  android:layout_height="wrap_content">
15 
16  <TextViewandroid:id="@+id/title"
17  android:layout_width="wrap_content"
18  android:layout_height="wrap_content"
19  android:textColor="#FFFFFFFF"
20  android:textSize="22px"/>
21  <TextViewandroid:id="@+id/info"
22  android:layout_width="wrap_content"
23  android:layout_height="wrap_content"
24  android:textColor="#FFFFFFFF"
25  android:textSize="13px"/>
26 
27  </LinearLayout>
28 
29 
30  </LinearLayout>

下面是實現代碼:


01 
05  publicclassMyListView3extendsListActivity {
06 
07 
08  // private List<String> data = new ArrayList<String>();
09  @Override
10  publicvoidonCreate(Bundle savedInstanceState) {
11  super.onCreate(savedInstanceState);
12 
13  SimpleAdapter adapter =newSimpleAdapter(this,getData(),R.layout.vlist,
14  newString[]{"title","info","img"},
15  newint[]{R.id.title,R.id.info,R.id.img});
16  setListAdapter(adapter);
17  }
18 
19  privateList<Map<String, Object>> getData() {
20  List<Map<String, Object>> list =newArrayList<Map<String, Object>>();
21 
22  Map<String, Object> map =newHashMap<String, Object>();
23  map.put("title","G1");
24  map.put("info","google 1");
25  map.put("img", R.drawable.i1);
26  list.add(map);
27 
28  map =newHashMap<String, Object>();
29  map.put("title","G2");
30  map.put("info","google 2");
31  map.put("img", R.drawable.i2);
32  list.add(map);
33 
34  map =newHashMap<String, Object>();
35  map.put("title","G3");
36  map.put("info","google 3");
37  map.put("img", R.drawable.i3);
38  list.add(map);
39 
40  returnlist;
41  }
42  }

使用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


01  <?xmlversion="1.0"encoding="utf-8"?>
02  <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
03  android:orientation="horizontal"
04  android:layout_width="fill_parent"
05  android:layout_height="fill_parent">
06 
07 
08  <ImageViewandroid:id="@+id/img"
09  android:layout_width="wrap_content"
10  android:layout_height="wrap_content"
11  android:layout_margin="5px"/>
12 
13  <LinearLayoutandroid:orientation="vertical"
14  android:layout_width="wrap_content"
15  android:layout_height="wrap_content">
16 
17  <TextViewandroid:id="@+id/title"
18  android:layout_width="wrap_content"
19  android:layout_height="wrap_content"
20  android:textColor="#FFFFFFFF"
21  android:textSize="22px"/>
22  <TextViewandroid:id="@+id/info"
23  android:layout_width="wrap_content"
24  android:layout_height="wrap_content"
25  android:textColor="#FFFFFFFF"
26  android:textSize="13px"/>
27 
28  </LinearLayout>
29 
30 
31  <Buttonandroid:id="@+id/view_btn"
32  android:layout_width="wrap_content"
33  android:layout_height="wrap_content"
34  android:text="@string/s_view_btn"
35  android:layout_gravity="bottom|right"/>
36  </LinearLayout>
程序代碼:
view sourceprint?
001
005 publicclassMyListView4extendsListActivity {
006
007
008 privateList<Map<String, Object>> mData;
009
010 @Override
011 publicvoidonCreate(Bundle savedInstanceState) {
012 super.onCreate(savedInstanceState);
013 mData = getData();
014 MyAdapter adapter =newMyAdapter(this);
015 setListAdapter(adapter);
016 }
017
018 privateList<Map<String, Object>> getData() {
019 List<Map<String, Object>> list =newArrayList<Map<String, Object>>();
020
021 Map<String, Object> map =newHashMap<String, Object>();
022 map.put("title","G1");
023 map.put("info","google 1");
024 map.put("img", R.drawable.i1);
025 list.add(map);
026
027 map =newHashMap<String, Object>();
028 map.put("title","G2");
029 map.put("info","google 2");
030 map.put("img", R.drawable.i2);
031 list.add(map);
032
033 map =newHashMap<String, Object>();
034 map.put("title","G3");
035 map.put("info","google 3");
036 map.put("img", R.drawable.i3);
037 list.add(map);
038
039 returnlist;
040 }
041
042 // ListView 中某項被選中後的邏輯
043 @Override
044 protectedvoidonListItemClick(ListView l, View v,intposition,longid) {
045
046 Log.v("MyListView4-click", (String)mData.get(position).get("title"));
047 }
048
049
052 publicvoidshowInfo(){
053 newAlertDialog.Builder(this)
054 .setTitle("我的listview")
055 .setMessage("介紹...")
056 .setPositiveButton("確定",newDialogInterface.OnClickListener() {
057 @Override
058 publicvoidonClick(DialogInterface dialog,intwhich) {
059 }
060 })
061 .show();
062
063 }
064
065
066
067 publicfinalclassViewHolder{
068 publicImageView img;
069 publicTextView title;
070 publicTextView info;
071 publicButton viewBtn;
072 }
073
074
075 publicclassMyAdapterextendsBaseAdapter{
076
077 privateLayoutInflater mInflater;
078
079
080 publicMyAdapter(Context context){
081 this.mInflater = LayoutInflater.from(context);
082 }
083 @Override
084 publicintgetCount() {
085 // TODO Auto-generated method stub
086 returnmData.size();
087 }
088
089 @Override
090 publicObject getItem(intarg0) {
091 // TODO Auto-generated method stub
092 returnnull;
093 }
094
095 @Override
096 publiclonggetItemId(intarg0) {
097 // TODO Auto-generated method stub
098 return0;
099 }
100
101 @Override
102 publicView getView(intposition, View convertView, ViewGroup parent) {
103
104 ViewHolder holder =null;
105 if(convertView ==null) {
106
107 holder=newViewHolder();
108
109 convertView = mInflater.inflate(R.layout.vlist2,null);
110 holder.img = (ImageView)convertView.findViewById(R.id.img);
111 holder.title = (TextView)convertView.findViewById(R.id.title);
112 holder.info = (TextView)convertView.findViewById(R.id.info);
113 holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);
114 convertView.setTag(holder);
115
116 }else{
117
118 holder = (ViewHolder)convertView.getTag();
119 }
120
121
122 holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));
123 holder.title.setText((String)mData.get(position).get("title"));
124 holder.info.setText((String)mData.get(position).get("info"));
125
126 holder.viewBtn.setOnClickListener(newView.OnClickListener() {
127
128 @Override
129 publicvoidonClick(View v) {
130 showInfo();
131 }
132 });
133
134
135 returnconvertView;
136 }
137
138 }
139
140
141
142
143 }

  下面將對上述代碼,做詳細的解釋,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問題


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