Android ListVeiw控制元件(轉載整理)

發表於2017-03-31

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

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
/**
 * @author allin
 *
 */
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()完成適配的最後工作。執行後的現實結構如下圖:

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
/**
 * @author allin
 *
 */
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>

執行後效果如下圖:

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
/**
 * @author allin
 *
 */
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的各元素上,完成適配。

執行效果如下圖:

有按鈕的ListView

但是有時候,列表不光會用來做顯示用,我們同樣可以在在上面新增按鈕。新增按鈕首先要寫一個有按鈕的xml檔案,然後自然會想到用上面的方法定義一個介面卡,然後將資料對映到佈局檔案上。但是事實並非這樣,因為按鈕是無法對映的,即使你成功的用佈局檔案顯示出了按鈕也無法新增按鈕的響應,這時就要研究一下ListView是如何現實的了,而且必須要重寫一個類繼承BaseAdapter。下面的示例將顯示一個按鈕和一個圖片,兩行字如果單擊按鈕將刪除此按鈕的所在行。並告訴你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
/**
 * @author allin
 *
 */
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"));
    }
     
    /**
     * listview中點選按鍵彈出對話方塊
     */
    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 0;
        }
 
        @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了。

執行效果如下圖:

相關文章