主程式 MyListView.java
public class MyListView extends ListActivity {
//預先定義順序常數
protected static final int MyListView_camera = 0,
MyListView_album = 1, MyListView_map = 2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//設定此Activity使用的res layout
setContentView(R.layout.list);
//設定ListView未取得內容時顯示的view, empty建構在list.xml中。
getListView().setEmptyView(findViewById(R.id.empty));
//自訂方法載入ListView值
fillData();
}
//當ListView的項目被按下
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
//由觸發的View物件v(即按下的那一列)取得adapter的checkbox
CheckBox cbx = (CheckBox)v.findViewById(R.id.MyAdapter_CheckBox_checkBox);
//取得adapter的textview
TextView title = (TextView)v.findViewById(R.id.MyAdapter_TextView_title);
if(cbx.isChecked()){
//設定可見checkbox的狀態
cbx.setChecked(false);
Toast.makeText(this, title.getText().toString() + "已取消核取!",
Toast.LENGTH_SHORT).show();
}else{
cbx.setChecked(true);
Toast.makeText(this, title.getText().toString() + "已核取!",
Toast.LENGTH_SHORT).show();
}
super.onListItemClick(l, v, position, id);
}
void fillData(){
//從res string.xml讀出預先寫好的字串陣列
CharSequence[] list = getResources().getStringArray(R.array.list);
setListAdapter(new MyAdapter(this, list));
}
}
MyAdapter.java
package iamshiao.sample;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter{
private LayoutInflater myInflater;
CharSequence[] list = null;
public MyAdapter(Context ctxt, CharSequence[] list){
myInflater = LayoutInflater.from(ctxt);
this.list = list;
}
@Override
public int getCount()
{
return list.length;
}
@Override
public Object getItem(int position)
{
return list[position];
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position,View convertView,ViewGroup parent)
{
//自訂類別,表達個別listItem中的view物件集合。
ViewTag viewTag;
if(convertView == null){
//取得listItem容器 view
convertView = myInflater.inflate(R.layout.adapter, null);
//建構listItem內容view
viewTag = new ViewTag(
(ImageView)convertView.findViewById(
R.id.MyAdapter_ImageView_icon),
(TextView) convertView.findViewById(
R.id.MyAdapter_TextView_title),
(CheckBox) convertView.findViewById(
R.id.MyAdapter_CheckBox_checkBox)
);
//設置容器內容
convertView.setTag(viewTag);
}
else{
viewTag = (ViewTag) convertView.getTag();
}
//設定內容圖案
switch(position){
case MyListView.MyListView_camera:
viewTag.icon.setBackgroundResource(R.drawable.ic_launcher_camera);
break;
case MyListView.MyListView_album:
viewTag.icon.setBackgroundResource(R.drawable.ic_launcher_gallery);
break;
case MyListView.MyListView_map:
viewTag.icon.setBackgroundResource(R.drawable.ic_launcher_maps);
break;
}
//設定內容文字
viewTag.title.setText(list[position]);
return convertView;
}
//自訂類別,表達個別listItem中的view物件集合。
class ViewTag{
ImageView icon;
TextView title;
CheckBox cbx;
public ViewTag(ImageView icon, TextView title, CheckBox cbx){
this.icon = icon;
this.title = title;
this.cbx = cbx;
}
}
}
list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<TextView
android:id="@+id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/empty"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
</LinearLayout>
adapter.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/MyAdapter_ImageView_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10px"
/>
<TextView
android:id="@+id/MyAdapter_TextView_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15px"
android:layout_toRightOf="@id/MyAdapter_ImageView_icon"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceLarge"
android:minHeight="?android:attr/listPreferredItemHeight"
/>
<CheckBox android:id="@+id/MyAdapter_CheckBox_checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5px"
android:layout_alignParentRight="true"
android:minHeight="?android:attr/listPreferredItemHeight"
android:focusable="false"
android:clickable="false"
/>
</RelativeLayout>
MyListView是清單的主要程式,Myadapter則是用來定義清單格式;所以MyListView讀取list這一個給清單用的xml檔,而Myadapter則是載入adapter這個定義每項清單內容的外觀的xml檔。
CharSequence[] list = getResources().getStringArray(R.array.list);取得預先存在values/string.xml的字串陣列。
string.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, Sample!</string>
<string name="app_name">Sample</string>
<string name="empty">無資料。</string>
<string-array name="list">
<item>相機</item>
<item>相簿</item>
<item>地圖</item>
</string-array>
</resources>
然後利用MyListView的setListAdapter()方法載入自訂的MyAdapter實體,藉此自訂MyListView的內容格式。
MyListView的另一個重點是
//當ListView的項目被按下
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
//由觸發的View物件v(即按下的那一列)取得adapter的checkbox
CheckBox cbx = (CheckBox)v.findViewById(R.id.MyAdapter_CheckBox_checkBox);
//取得adapter的textview
TextView title = (TextView)v.findViewById(R.id.MyAdapter_TextView_title);
if(cbx.isChecked()){
//設定可見checkbox的狀態
cbx.setChecked(false);
Toast.makeText(this, title.getText().toString() + "已取消核取!",
Toast.LENGTH_SHORT).show();
}else{
cbx.setChecked(true);
Toast.makeText(this, title.getText().toString() + "已核取!",
Toast.LENGTH_SHORT).show();
}
super.onListItemClick(l, v, position, id);
}
在這個部分由於我在adapter.xml中將CheckBox設定成無法核取也無法聚焦,
<CheckBox android:id="@+id/MyAdapter_CheckBox_checkBox"
...
android:focusable="false"
android:clickable="false"
/>
再另用onListItemClick這個事件讓項目被按下時再去核取內容的CheckBox,如果不這麼設定的話,項目的按下與CheckBox的按下將被視為不同兩件事,當然如果你的需求本來就是要視為兩個不同元件分開按,就不必做上述設定。
首先我先用一個自訂類別來表達每一個list項目的內容...
//自訂類別,表達個別listItem中的view物件集合。
class ViewTag{
ImageView icon;
TextView title;
CheckBox cbx;
public ViewTag(ImageView icon, TextView title, CheckBox cbx){
this.icon = icon;
this.title = title;
this.cbx = cbx;
}
}
@Override
public View getView(int position,View convertView,ViewGroup parent)
{
//自訂類別,表達個別listItem中的view物件集合。
ViewTag viewTag;
if(convertView == null){
//取得listItem容器 view
convertView = myInflater.inflate(R.layout.adapter, null);
//建構listItem內容view
viewTag = new ViewTag(
(ImageView)convertView.findViewById(
R.id.MyAdapter_ImageView_icon),
(TextView) convertView.findViewById(
R.id.MyAdapter_TextView_title),
(CheckBox) convertView.findViewById(
R.id.MyAdapter_CheckBox_checkBox)
);
//設置容器內容
convertView.setTag(viewTag);
}
else{
viewTag = (ViewTag) convertView.getTag();
}
...
}
完成內容榜定後我們要接著做內容的填入,利用在MyListView中宣告的常數我們可以區別出哪張圖片應該要載入進第幾個清單項目的icon中...
//設定內容圖案
switch(position){
case MyListView.MyListView_camera:
viewTag.icon.setBackgroundResource(R.drawable.ic_launcher_camera);
break;
case MyListView.MyListView_album:
viewTag.icon.setBackgroundResource(R.drawable.ic_launcher_gallery);
break;
case MyListView.MyListView_map:
viewTag.icon.setBackgroundResource(R.drawable.ic_launcher_maps);
break;
}
還有填入標題
viewTag.title.setText(list[position]);
以上就完成了一個客製化的ListView,另外要 特別注意當ListView項目大於畫面所能承載(一般是6個項目),那隨著捲軸捲動,CheckBox等控制項元件的狀態會流失(已勾選的會被消掉)。 你必須主動在adapter中撰寫狀態記憶用的程式,這個部分之後如果有寫SQLite搭配ListView的教學會再詳述。
转载地址:http://iamshiao.blogspot.com/2010/12/androidbaseadapterlistview.html