Android開發——ListView的運用

Android開發經驗總結——ListView的使用

Android中ListView這個組件比較常用,但對初學者來說,又比較難掌握,在此分享一下我的使用經驗。
ListView是以列表的形式展示數據,這裏面有三個要素:數據、視圖、適配器。
常用的適配器有三種:ArrayAdapter, SimpleAdapter, SimpleCursorAdapter。
其中SimpleAdapter擴展性最好,幾乎能實現所有展示需求的列表,我在實際開發中用的全是這個,這裏也只介紹這個。

假設要實現如下效果的列表視圖:


下面一步步來實現。

首先設計視圖,主要設計ListView裏面item的顯示效果,在layout中創建item.xml文件,如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" android:layout_height="75dp"
	android:paddingLeft="10dp" android:paddingRight="10dp">
	<ImageView
		android:id="@+id/img"
		android:layout_height="fill_parent"
		android:layout_width="60dp"
		android:layout_alignParentLeft="true" />
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:orientation="vertical" android:layout_height="fill_parent"
		android:layout_width="fill_parent" android:layout_toRightOf="@id/img"
		android:paddingLeft="8dp">
		<TextView
			android:id="@+id/title1"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textColor="#cbcaca"
			android:textSize="20dp" />
		<TextView
			android:id="@+id/title2"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textColor="#cbcaca"
			android:textSize="14dp" />
		<TextView
			android:id="@+id/time"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textColor="#cbcaca"
			android:textSize="12dp" />
	</LinearLayout>
	<CheckBox
		android:id="@+id/checked"
		android:layout_height="fill_parent"
		android:layout_width="wrap_content"
		android:layout_alignParentRight="true"
		android:checked="false"
		android:focusable="false" />
</RelativeLayout>

此xml文件定義列表中每個項目的佈局,如果想要不同的佈局,修改此文件的佈局即可。

這個文件中給每個需要在程序中動態賦值的地方都取了id,看到後面的代碼時,注意對應關係。

 

然後是適配器和數據,這兩個聯繫比較緊密,就放一起了。

先上代碼:

//獲取ListView對象
ListView mListView = (ListView)findViewById(R.id.listview);
//下面是數據映射關係,mFrom和mTo按順序一一對應
String[] mFrom = new String[]{"img","title1","title2","time"};
int[] mTo = new int[]{R.id.img,R.id.title1,R.id.title2,R.id.time};
//獲取數據,這裏隨便加了10條數據,實際開發中可能需要從數據庫或網絡讀取
List<Map<String,Object>> mList = new ArrayList<Map<String,Object>>();
Map<String,Object> mMap = null;
for(int i = 0;i < 10;i++){
	mMap = new HashMap<String,Object>();
	mMap.put("img", R.drawable.icon);
	mMap.put("title1", "標題");
	mMap.put("title2", "副標題");
	mMap.put("time", "2011-08-15 09:00");
	mList.add(mMap);
}
//創建適配器
SimpleAdapter mAdapter = new SimpleAdapter(this,mList,R.layout.item,mFrom,mTo);
mListView.setAdapter(mAdapter);

這裏要注意對應關係,Layout中的id,程序中對它的引用,Map中的數據。 

到這裏已經實現了上面那張圖的效果。但是程序需要一些交互操作,比如單擊某一項,長按某一項,怎麼辦?

看下面:

添加點擊事件:

mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		@SuppressWarnings("unchecked")
		//獲取被點擊的item所對應的數據
		HashMap<String,Object> map = (HashMap<String, Object>) parent.getItemAtPosition(position);
		//下面是你的其他事務邏輯
	}
});

這裏可以通過position獲取被點擊的item所對應的Map數據,拿到這個數據了,還怕有什麼功能實現不了嗎?

舉個最常見的例子,數據是從數據庫裏取的,每條數據有唯一的id,點了某一項之後,需要得到這個id進行數據操作,怎麼辦?很簡單,在準備數據的時候,往Map中多添加一條數據,map.put("id",id),在上面的事件處理中,可以通過(Long) map.get("id")來獲取id(此處假設id是long類型),取到id之後就可以進行數據庫操作了。放心,添加的額外數據不會影響View的顯示,因爲有對應關係在。

長按事件和這個類似,無非是註冊OnItemLongClickListener事件,在此就不列代碼了。

還有最後一個問題,界面中每個item後面顯示了一個單選框,明顯是爲批處理留的,該如何實現呢?

仔細想一下,會發現難點在於單選框狀態的記錄及獲取。下面是我的方法:

在定義SimpleAdapter對象的時候,重寫它的getView方法。如下:

mAdapter = new SimpleAdapter(this, pictureList, R.layout.picturelist, mFrom, mTo){
	@Override  
	public View getView(final int position, View convertView, ViewGroup parent) {
		View view = super.getView(position, convertView, parent);
		@SuppressWarnings("unchecked")
		final HashMap<String,Object> map = (HashMap<String, Object>) this.getItem(position);
		//獲取相應View中的Checkbox對象
		CheckBox checkBox = (CheckBox)view.findViewById(R.id.checked);
		checkBox.setChecked((Boolean) map.get("checked"));
		//添加單擊事件,在map中記錄狀態
		checkBox.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				map.put("checked", ((CheckBox)view).isChecked());
			}
		});
		return view;
	}
};

在其他地方獲取狀態並處理:

//獲取列表中的項目總數
int count = pictureListView.getCount();
Map<String,Object> map = null;
boolean isChecked;
long id;
for(int i = 0;i < count;i++){
	map = (Map<String, Object>) pictureListView.getItemAtPosition(i);
	isChecked = (Boolean) map.get("isChecked");
	if(isChecked){
		id = (Long) map.get("id");
		//被選中的邏輯
	}
	else{
		id = (Long) map.get("id");
		//未被選中的邏輯
	}
}
//如果操作過程中對列表內容進行了添加或刪除,需要調用下面這個方法來更新視圖
mAdapter.notifyDataSetChanged();

還有一點忘了寫了,demo中的圖片是drawable裏面的圖片,如果map中只有圖片的地址,如何把它轉成drawable對象顯示出來呢?我在這裏也研究了好久,map中放入drawable對象傳過去好像沒用,不會顯示,怎麼辦?好在前面有重寫SimpleAdapter的getView方法。map中把圖片地址放進去,在getView方法裏面,把此地址轉成drawable對象,然後設置給ImageView,大功告成!代碼如下:

mAdapter = new SimpleAdapter(this, pictureList, R.layout.picturelist, mFrom, mTo){
	@Override  
	public View getView(final int position, View convertView, ViewGroup parent) {
		View view = super.getView(position, convertView, parent);
		@SuppressWarnings("unchecked")
		final HashMap<String,Object> map = (HashMap<String, Object>) this.getItem(position);
		ImageView imageView = (ImageView)view.findViewById(R.id.img);
		FileInputStream fin;
		try {
			if(map.get("img") == null){
				throw new IOException();
			}
			fin = getApplicationContext().openFileInput((String) map.get("img"));
			imageView.setImageDrawable(Drawable.createFromStream(fin, "src"));
			fin.close();
		} catch (FileNotFoundException e) {
			imageView.setImageResource(R.drawable.default);
		} catch (IOException e) {
			imageView.setImageResource(R.drawable.default);
		}
		return view;
	}
};

發佈了13 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章