实现的界面效果如下图所示,没有可以进行布局上的调整,所以看起来丑一点。
上图在一个ListView中显示了两种不同的ItemView,主要是使用BaseAdapter中的getItemViewType()方法,以及getViewTypeCount()方法实现的。
下面来说说详细的实现步骤:
1. 跟以前使用自定义adapter时一样,都需要编写itemView的xml布局文件。只不过在此例中需要编写两个xml布局文件,分别对应了两个不同的itemView。两个xml文件的代码如下:
布局1
布局2
2.自定义一个Adapter类继承自BaseAdapter。并实现
getItemViewType()方法,以及getViewTypeCount()方法。顾名思义,getItemViewType()方法是用来获取当前需要绘制的itemView的类型,getViewTypeCount()方法是用来获取不同的itemview的种类数,即总共有多少种不同种类的itemView。
自定义适配器的代码如下:
/**
* Created by Kent on 2014/12/12.
*/
public class MyAdapter extends BaseAdapter {
private Context mContext = null;//上下文
private LayoutInflater mInflater = null;
private List<BaseItem> mData = null;//要显示的数据
public MyAdapter(Context context, List<BaseItem> data){
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
//添加一个新的Item,并通知listview进行显示刷新
public void addItem(BaseItem newItem){
this.mData.add(newItem);
this.notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
return mData.get(position).getItem_type();
}
@Override
public int getViewTypeCount() {
return ItemType.ITEM_TYPE_MAX_COUNT;
}
@Override
public int getCount() {
if(mData == null){
return 0;
}
return this.mData.size();
}
@Override
public Object getItem(int i) {
return mData.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
View viewItem1 = null;
View viewItem2 = null;
int itemType = this.getItemViewType(position);
if(itemType == ViewHolder1.ITEM_VIEW_TYPE_1){
//第一种item
ViewHolder1 viewHolder1 = null;
if(convertView == null){
//没有缓存过
viewHolder1 = new ViewHolder1();
viewItem1 = this.mInflater.inflate(R.layout.list_view_item_1, null, false);
viewHolder1.textView = (TextView)viewItem1.findViewById(R.id.
main_activity_list_view_item_1_textview);
viewHolder1.imageView = (ImageView)viewItem1.findViewById(R.id.
main_activity_list_view_item_1_imageview);
viewItem1.setTag(viewHolder1);
convertView = viewItem1;
}else{
viewHolder1 = (ViewHolder1)convertView.getTag();
}
viewHolder1.textView.setText(((ItemBean1) mData.get(position)).getName());
viewHolder1.imageView.setBackgroundResource(R.drawable.ic_launcher);
}else if(itemType == ViewHolder2.ITEM_VIEW_TYPE_2){
//第二种item
ViewHolder2 viewHolder2 = null;
if(convertView == null){
//没有缓存过
viewHolder2 = new ViewHolder2();
viewItem2 = this.mInflater.inflate(R.layout.list_view_item_2, null, false);
viewHolder2.textView1 = (TextView)viewItem2.findViewById(R.id.
main_activity_list_view_item_2_textview);
viewHolder2.textView2 = (TextView)viewItem2.findViewById(R.id.
main_activity_list_view_item_2_textview_2);
viewItem2.setTag(viewHolder2);
convertView = viewItem2;
}else{
viewHolder2 = (ViewHolder2)convertView.getTag();
}
viewHolder2.textView1.setText(((ItemBean2)mData.get(position)).getName());
viewHolder2.textView2.setText(((ItemBean2)mData.get(position)).getAddress());
}
return convertView;
}
}
首先要说一下listview的绘制原理,在listview进行绘制的时候,首先要调用getCount()方法来确定listview的item个数,然后在绘制每个item的时候调用getView方法来进行绘制,而getItem和getItemId是在listview响应用户操作时间时候进行调用的。
这里着重介绍一下getView()方法,这个方法是在绘制每个item时进行调用的,它返回一个View对象,而此View就是需要绘制的View。
public View getView(int position, View convertView, ViewGroup viewGroup):其中position参数为当前绘制的item的位置,convertView参数为当前要绘制的View,这个参数主要用来缓存,viewGroup参数是当前view的父控件。
关于
getItemViewType()方法,以及getViewTypeCount()方法将在稍后进行讨论。
3. listview数据源:
通常listview里面的数据是来源于一个list集合,而list集合中的元素是Map类型的数据。即:List<Map<String, Object>>每个map类型的数据对应了一个itemview中需要显示的内容。而本例中定义数据源是来自对象的,由于本例要显示不同的item,所以我们自定义出两个Bean,分别对应两种item中的数据。代码如下:
/**
* Created by Kent on 2014/12/15.
*/
public class BaseItem {
private int item_type = 0;
public BaseItem(int item_type) {
this.item_type = item_type;
}
public int getItem_type() {
return item_type;
}
public void setItem_type(int item_type) {
this.item_type = item_type;
}
}
由于每个Item都需要一个type类型的变量来标识当前Item的种类,所以定义了一个基类:BaseItem类,它只包含一个item_type的属性,用来标识item的种类。
两个继承自它的子类:
/**
* Created by Kent on 2014/12/15.
*/
public class ItemBean1 extends BaseItem{
private String name = null;
private String imagePath = null;
public ItemBean1(int item_type, String name, String imagePath) {
super(item_type);
this.name = name;
this.imagePath = imagePath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public int getItemType(){
return super.getItem_type();
}
public void setItemType(int itemType){
super.setItem_type(itemType);
}
}
4. MainActivity中的代码:
public class MainActivity extends Activity {
private ListView listView = null;
//适配器
private MyAdapter myAdapter = null;
//数据
private List<BaseItem> mData = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewsById();;
init();
addListeners();
}
private void findViewsById(){
this.listView = (ListView)findViewById(R.id.main_activity_listview);
}
private void init(){
this.mData = new ArrayList<BaseItem>();
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name1", "iamgePath1"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean1(ViewHolder1.ITEM_VIEW_TYPE_1, "name2", "iamgePath2"));
this.mData.add(new ItemBean2(ViewHolder2.ITEM_VIEW_TYPE_2, "name1", "address1"));
this.myAdapter = new MyAdapter(this, this.mData);
this.listView.setAdapter(this.myAdapter);
}
private void addListeners(){
}
}
5. ViewHolder,用于ItemView的缓存优化:
/**
* Created by Kent on 2014/12/12.
*/
public final class ViewHolder1 {
public static final int ITEM_VIEW_TYPE_1 = 0;
public TextView textView = null;
public ImageView imageView = null;
}
/**
* Created by Kent on 2014/12/12.
*/
public final class ViewHolder2 {
public static final int ITEM_VIEW_TYPE_2 = 1;
public TextView textView1 = null;
public TextView textView2 = null;
}
/**
* Created by Kent on 2014/12/15.
*/
public class ItemType {
public static final int ITEM_TYPE_MAX_COUNT = 2;
}
6. 实现不同item类型的显示;
首先来看下getItemViewType()方法;
public int getItemViewType(int position) {
return mData.get(position).getItem_type();
}
这个方法返回了当前要绘制的ItemView的类型,类型数据存储在listView的数据源List中的每个bean的itemType属性中。
再来看看getViewTypeCount()方法:
public int getViewTypeCount() {
return ItemType.ITEM_TYPE_MAX_COUNT;
}
这个方法返回了不同Item的种类个数。
最后来看看最重要的getView()方法:
public View getView(int position, View convertView, ViewGroup viewGroup) {
View viewItem1 = null;
View viewItem2 = null;
int itemType = this.getItemViewType(position);
if(itemType == ViewHolder1.ITEM_VIEW_TYPE_1){
//第一种item
ViewHolder1 viewHolder1 = null;
if(convertView == null){
//没有缓存过
viewHolder1 = new ViewHolder1();
viewItem1 = this.mInflater.inflate(R.layout.list_view_item_1, null, false);
viewHolder1.textView = (TextView)viewItem1.findViewById(R.id.
main_activity_list_view_item_1_textview);
viewHolder1.imageView = (ImageView)viewItem1.findViewById(R.id.
main_activity_list_view_item_1_imageview);
viewItem1.setTag(viewHolder1);
convertView = viewItem1;
}else{
viewHolder1 = (ViewHolder1)convertView.getTag();
}
viewHolder1.textView.setText(((ItemBean1) mData.get(position)).getName());
viewHolder1.imageView.setBackgroundResource(R.drawable.ic_launcher);
}else if(itemType == ViewHolder2.ITEM_VIEW_TYPE_2){
//第二种item
ViewHolder2 viewHolder2 = null;
if(convertView == null){
//没有缓存过
viewHolder2 = new ViewHolder2();
viewItem2 = this.mInflater.inflate(R.layout.list_view_item_2, null, false);
viewHolder2.textView1 = (TextView)viewItem2.findViewById(R.id.
main_activity_list_view_item_2_textview);
viewHolder2.textView2 = (TextView)viewItem2.findViewById(R.id.
main_activity_list_view_item_2_textview_2);
viewItem2.setTag(viewHolder2);
convertView = viewItem2;
}else{
viewHolder2 = (ViewHolder2)convertView.getTag();
}
viewHolder2.textView1.setText(((ItemBean2)mData.get(position)).getName());
viewHolder2.textView2.setText(((ItemBean2)mData.get(position)).getAddress());
}
return convertView;
}
前面已经说过了,getView是在每个Item进行绘制的时候进行调用的,那么想要进行不同类型Item的显示,在这个方法中根据item的类型进行不同的绘制就可以了。
首先,通过
int itemType = this.getItemViewType(position);
获取到当前要绘制的Item的种类。然后根据不同的种类进行不同的布局导入。
viewItem1 = this.mInflater.inflate(R.layout.list_view_item_1, null, false);
这个方法使用了ViewHolder进行itemView的缓存。有关内容在此不做解释
源码下载地址:http://download.csdn.net/detail/hhzz1504042001/8262015