1. 程式人生 > >Android ListView基礎篇

Android ListView基礎篇

本系列文章將為大家總結如何快速使用ListView以及做到高效的ListView,本篇博文介紹ListView的基本使用

ListView&Adapter

ListView是Android中用來顯示一個列表的資料的控制元件,幾乎大部分的應用都會用到,它以列表的形式展示具體內容,並且能夠根據資料的長度自適應顯示,ListView繼承至AdapterView,它的展示是要通過一個adapter來完成,adapter裡面裝載資料,ListView再通過adapter的資料來進行每一個Item的展示。如下圖:


Adapter在ListView的使用中起著至關重要的作用。它是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的優化,希望對大家有所幫助。