一般情况下,ListView中的Item的类型的都是相同的,即每个Item的布局都调用的同一个XML。但是我们现在的需求需要ListView包含多种类型,需要如何实现呢?
是的,就是覆写Adapter的getItemViewType(int position)和get ViewTypeCount()方法。
getItemViewType(int position)代表第position个Item的类型是什么,返回值为 int值。并且在getView中调用这个方法,并且根据返回值值的类型加载不同的布局。
get ViewTypeCount()表示Item类型种类的个数。
这里我们实现3中类型的Item。
首先构建3个ViewHolder类型,然后根据getItemViewType的返回值,在getView中加载不同ViewHolder。
这里不知道ViewHolder的同学,请看Android之ListView性能优化 里面讲解了通过convertView以及ViewHolder来优化ListView性能
package com.example.listviewbaseadapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class BaseAdapterListView extends Activity {
private ListView listview;
private List<Map<String, Object>> data; // List集合中的对象是一个Map对象,而这个Map对象的键是String类型,值是Object类型
public final static int Type_1 = 0;
public final static int Type_2 = 1;
public final static int Type_3 = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base_adapter_list_view);
listview = (ListView) findViewById(R.id.lv);
listview.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
Log.d("base", "item has worked");
}
});
// 将要绑定的数据赋给data
data = getData();
MyAdapter adapter = new MyAdapter(this);
listview.setAdapter(adapter);
}
private List<Map<String, Object>> getData() {
// TODO Auto-generated method stub
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map;
// 遍历
for (int x = 0; x < 50; x++) {
map = new HashMap<String, Object>();
map.put("button", "button" + x);
map.put("text1", "优化ListView" + x);
map.put("text2", "重写BaseAdapter" + x);
list.add(map);
}
Log.v("myu", "list count="+list.size());
return list;
}
// 通过ViewHolder静态类结合缓存convertView优化ListView性能
// 使用 ViewHolder 的好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。
static class ViewHolder1 {
public Button btn;
public TextView text1;
public TextView text2;
}
static class ViewHolder2 {
public TextView text3;
}
static class ViewHolder3 {
public ImageView imageView3;
}
public class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater = null;
private MyAdapter(Context context) {
// 根据context上下文加载布局
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
Log.v("myu", "getCount()");
// TODO Auto-generated method stub
// 在此适配器中所代表的数据集中的条目数
// 系统首先调用getCount()函数,根据他的返回值得到listView的长度,然后根据这个长度,调用getView()逐一绘制每一行
// 如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。
return data.size();
}
@Override
public Object getItem(int position) {
Log.v("myu", "getItem(" +position +")");
// TODO Auto-generated method stub
// 获取数据集中与指定索引对应的数据项
return position;
}
@Override
public long getItemId(int position) {
Log.v("myu", "getItemId(" +position +")");
// TODO Auto-generated method stub
// 获取在列表中与指定索引对应的行id
return position;
}
@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
Log.v("myu", "getItemViewType " + position);
if (position % 3 == 0) {
return Type_1;
} else if (position % 3 == 1) {
return Type_2;
} else {
return Type_3;
}
}
@Override
public int getViewTypeCount() {
Log.v("myu", "getViewTypeCount() ");
// TODO Auto-generated method stub
return 3;
}
// 获取一个在数据集中指定索引的视图来显示数据
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
Log.v("myu", "getView("+ position+") ");
// TODO Auto-generated method stub
ViewHolder1 holder = null;
ViewHolder2 holder2 = null;
ViewHolder3 holder3 = null;
int type = getItemViewType(position);
Log.v("myu", "getView " + position + " " + convertView + " type = "
+ type);
// 如果缓存convertView为空,则需要创建View
if (convertView == null) {
switch (type) {
case Type_1:
holder = new ViewHolder1();
convertView = mInflater.inflate(R.layout.item, null);
holder.btn = (Button) convertView.findViewById(R.id.btn1);
holder.btn.setText("button"+position);
holder.text1 = (TextView) convertView
.findViewById(R.id.text1);
holder.text2 = (TextView) convertView
.findViewById(R.id.text2);
// 将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag
// 绑定ViewHolder对象
convertView.setTag(holder);
break;
case Type_2:
holder2 = new ViewHolder2();
convertView = mInflater.inflate(R.layout.item2, null);
holder2.text3 = (TextView) convertView
.findViewById(R.id.text3);
holder2.text3.setText(data.get(position).get("text1")
.toString());
convertView.setTag(holder2);
break;
case Type_3:
holder3 = new ViewHolder3();
convertView = mInflater.inflate(R.layout.item3, null);
holder3.imageView3 = (ImageView) convertView
.findViewById(R.id.imageView);
convertView.setTag(holder2);
break;
default:
break;
}
} else {
switch (type) {
case Type_1:
holder = (ViewHolder1) convertView.getTag();// 取出ViewHolder对象
/** 设置控件显示的内容,即我们存放在动态数组中的数据 */
holder.btn.setText((String) data.get(position)
.get("button")); // 通过get("button")
// 与MAP做KEY对应
holder.text1.setText((String) data.get(position).get(
"text1"));
holder.text2.setText((String) data.get(position).get(
"text2"));
holder.btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("base", "你点击了按钮");
data.remove(position); // 移除该item
MyAdapter.this.notifyDataSetChanged(); // 刷新ListView
}
});
break;
case Type_2:
holder2 = (ViewHolder2) convertView.getTag();
holder2.text3.setText(data.get(position).get("text1")
.toString());
break;
case Type_3:
holder3 = (ViewHolder3) convertView.getTag();
break;
default:
break;
}
}
return convertView;
}
}
}
效果图:
三种类型的Item分别为一个包含Button和两个TextView、一个只包含TextView、一个只包含ImageView