Android ListView基礎篇
本系列文章將為大家總結如何快速使用ListView以及做到高效的ListView,本篇博文介紹ListView的基本使用
ListView&Adapter
ListView是Android中用來顯示一個列表的資料的控制元件,幾乎大部分的應用都會用到,它以列表的形式展示具體內容,並且能夠根據資料的長度自適應顯示,ListView繼承至AdapterView,它的展示是要通過一個adapter來完成,adapter裡面裝載資料,ListView再通過adapter的資料來進行每一個Item的展示。如下圖:
Adapter在ListView的使用中起著至關重要的作用。它是ListView展示與後臺資料之間的橋樑
1.建立或獲得資料,包括圖片或者文字內容
2.構建一個adapter,將資料作為adapter的構造引數傳進去
3.建立一個ListView,通過setAdapter(adapter)將構造好的adapter設定給ListView
ArrayAdapter的使用
下面以ArrayAdapter作為介面卡為例
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/mylistview" android:layout_width="fill_parent" android:layout_height="fill_parent"> </ListView> </LinearLayout>
1.建立或獲得資料
private List<String> getData(){
List<String> data = new ArrayList<String>();
data.add("第一項資料");
data.add("第二項資料");
data.add("第三項資料");
data.add("第四項資料");
return data;
}
定義這樣一個方法用來獲取資料,即要顯示在listview上的內容
2.構建一個adapter,將資料作為adapter的構造引數傳進去
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1,getData());
三個引數分別代表:
getContext()【傳入當前listview所在的上下文物件】
android.R.layout.simple_list_item_1 【每一個列表項的佈局,這裡的demo使用Android系統自帶的佈局】
getData() 【傳入一個List<String>物件,這裡使用第一步獲取到資料在進行填充】
3.建立一個ListView,通過setAdapter(adapter)將構造好的adapter設定給ListView
ListView mylistview = (ListView)this.findViewById(R.id.mylistview);
mylistview.setAdapter(adapter);
執行結果:
可以看到一個最簡單的列表,每個列表項只有一條文字資料,但你會發現,我們只能將資料展示,無法更改文字的大小或顏色等,接下來我們再將其改造一下,通過自定義佈局來構造adapter:
首先建立一個佈局檔案list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/list_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:textColor="#32A082"/>
</LinearLayout>
修改一下adapter的建構函式:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity().getApplicationContext(), R.layout.list_item, R.id.list_item_text,getData());
這裡多添加了一個引數,這個引數是佈局檔案中textView所對應的id
執行結果:
SimpleAdapter的使用
使用ArrayAdapter雖然簡單,但是它還是不能夠滿足我們的需求,大部分情況下,列表的內容不僅僅是文字,而是有圖片、圖示、多選框等各種控制元件的搭配,這種情況下就要用到另外一種常見的Adapter——SimpleAdapter.先在佈局檔案中新增一個ImageView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="@+id/list_item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"/>
<TextView
android:id="@+id/list_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:textColor="#32A082"/>
</LinearLayout>
由於SimpleAdapter的建構函式的引數是要求傳入一個List<? extends Map<String, ?>>型別的資料集,所以getData方法也要修改一下:
public List<Map<String, Object>> getData(){
List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
for(int i=0; i<4; i++){
Map<String, Object> map = new HashMap<String, Object>();
map.put("image", R.drawable.ic_launcher);
map.put("text", "第"+i+"項資料");
data.add(map);
}
return data;
}
其中,每一個map代表著列表中每一行的資料,這裡由於每一行只有一張圖片和一個文字,所以只需要往map中put進兩個鍵值
鍵是作為資料的標識,值是作為資料的內容。這裡迴圈了4次添加了4行資料
資料構造完畢,接下來就是要構造SimpleAdapter並setAdapter:
adapter = new SimpleAdapter(getContext(), getData(), R.layout.list_item,
new String[]{"image","text"},
new int[]{R.id.list_item_image,R.id.list_item_text});
mylistview.setAdapter(adapter);
可以看到,SimpleAdapter的建構函式中有5個引數,它們分別代表:
getContext() 【傳入當前listview所在的上下文物件】
R.layout.list_item 【每一個列表項的自定義佈局】
getData() 【傳入一個List<? extends Map<String, ?>>物件,這裡使用上一步獲取到資料在進行填充】
new String[]{"image","text"}【這裡是一個字串陣列,注意元素要一一對應資料集中map對應的那些鍵】
new int[]{R.id.list_item_image,R.id.list_item_text}【這裡一一對應每一行中每一個控制元件的資源ID】
執行結果:
ListView子控制元件的點選事件
在上面例子的基礎上,再往佈局檔案中新增一個button:<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="@+id/list_item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"/>
<TextView
android:id="@+id/list_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:paddingLeft="10dp"
android:textColor="#32A082"/>
<Button
android:id="@+id/list_item_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按鈕"
android:layout_marginLeft="15dp"/>
</LinearLayout>
執行之後,每一個列表項都多加了一個按鈕,但我們如何監聽每一個按鈕各自的onClick事件呢?直接在Activity中操作顯然不可能,無法區別每一個button,所以adapter同樣為我們提供了一個getView()方法,可以在這個方法中實現每一行的子控制元件的監聽事件。
首先,先建一個自定義Adapter類繼承於SimpleAdapter(其它比如BaseAdapter等也可以,都有getView方法),重寫其getCount()、getItem()、getItemtId()、getView()等方法,程式碼如下:
public class ListViewAdapter extends SimpleAdapter{
private Context context;
private List<Map<String,Object>> data;
public ListViewAdapter(Context context,
List<Map<String, Object>> data, int resource, String[] from,
int[] to) {
super(context, data, resource, from, to);
// TODO Auto-generated constructor stub
this.context = context;
this.data = data;
}
//返回資料的大小,即listview的行數
@Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}
//根據下標獲得某一行的資料
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data.get(position);
}
//獲得指定的Item的下標
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View v = super.getView(position, convertView, parent);
Button btn = (Button)v.findViewById(R.id.list_item_btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Toast.makeText(context, "點選了第"+position+"項", 1000).show();
}
});
return v;
}
}
程式碼分析:重點在於getView這個方法,它相當於重繪ListView每一行的元素,通過呼叫父類的getView()方法,獲得每一行的View的控制代碼,然後就可以根據這個控制代碼通過findViewById()來獲得list_item佈局檔案中的各個控制元件了,這裡為每一行的按鈕設定點選事件,並顯示當前點選的是哪一行(position代表的正是當前行的下標)
當然,還需要使用我們定義好的adapter類:
adapter = new ListViewAdapter(getActivity().getApplicationContext(), getData(), R.layout.list_item,
new String[]{"image","text"},
new int[]{R.id.list_item_image,R.id.list_item_text});
mylistview.setAdapter(adapter);
執行結果:
ListView焦點搶奪問題
執行以上demo時,你會發現點選按鈕雖然有反應了,但是ListView的每一行的點選事件卻失效了,這是由於Android規定了:一旦自定義listitem裡面含有子控制元件例如按鈕、下拉框等等的話預設是子控制元件獲得焦點,因此此時點選listitem時是無效的,所以應該在listItem的最底層那個父佈局上面加上:android:descendantFocusability="blocksDescendants"【表示會覆蓋子類控制元件而直接獲得焦點】
再次執行,就會發現子控制元件的點選事件有效果,每個ListItem的點選事件也有效果。
至此,我們就可以通過自定義形形色色的佈局檔案來構造我們的listView了,並且可以實現各自的監聽事件,這就是關於ListView的基本使用方式了,我在以後的博文中整合有關ListView的優化,希望對大家有所幫助。