一个ListView根据标识加载不同布局,很简单的例子,就是聊天界面,你说话在右边好友在左边怎么实现呢.

我不是一个标题党,我也是自己遇到了这个问题,想给后面的人一个快速解决的方法

  1. 我最开始的方法是通过将两个布局写在一个布局文件里, 通过显示和隐藏控件,来实现这样的效果,这样看起来重用的控件利用率高了呀,→_→,但是有时候控制的好揪心,难道就不能加载两个布局么,我来说一下尝试的方法

  2. 加载两个布局,肯定没问题,你只需要传入一个标识,我在getView()方法里根据position拿到相应的数据,拿到标识位,就可以去加载不同的布局了,这肯定可以,

但是,这样就不能用ViewHolder了因为第一次,你去使用ViewHolder的时候,判断convertView是否为空,第二次就是不为空了,从ViewHolder中取控件赋值了,这是关键点,你可以用两个ViewHolder存储,关键还是convertView的复用,


其实你只是没清楚convertView复用,我们有开发经验的朋友应该都知道ListView的缓存机制

ListView显示的view从我们重写的getView方法创建,并且一共创建的个数是一屏显示的个数比方说我们手机上一屏能显示3个item,那么ListView刚开始显示的时候就创建了3个ListView的item,而当我们向上滚动ListView的时候第一个item不可见,下面的第4个item并没有重新创建而实际上复用的是第一个item。这样设计的目的就是为我们节省了很大的内存开销。

在ListView的父类AbsListView中,有一个变量RecycleBin mRecycler
用来存储某一显示项布局对应的视图。实际存储在 ArrayList[] 中,
该数组的长度为getViewTypeCount的返回值。

RecycleBin 是AbsListView的一个内部类。 当ListView执行setAdapter方法时,mRecycler会重置,getViewTypeCount方法会被调用。当ListView要显示某一项时,getItemViewType方法被调用,根据返回值在mRecycler搜索得到缓存的视图(重点在这里!!!我们只需要在getItemViewType中做手脚即可)

这也是为什么getViewTypeCount返回值要比定义的视图类型常量值大的原因,否则会导致数组越界异常。然后调用getView方法,缓存的视图被传递给getView方法的convertView形参 , 当传递进来的convertView形参为null的话,需要根据该项的视图类型,初始化布局。最后给显示项填充数据。

我们滑动到让第4个item显示出来之前,首先会执行getItemViewType这个方法判断该行item的类型,然后再从缓存池中查看是否有该类型item的缓存给我们用,有的话就直接拿过来,没有就创建

getViewTypeCount()//告诉ListView我共有多少种item,
getItemViewType()//方法告诉ListView每行该显示哪种item,

并且该方法中返回的type类型必须为整数且不能大于getViewTypeCount返回的数。

//这是适配器的默认实现方法 也就只有一种布局类型
public int getItemViewType(int position){return 0;}
public int getViewTypeCount() {return 1;  }

关键代码

//在适配器定义两个类型常量 和一个类型总数量
public static final int TYPE_1= 0;
public static final int TYPE_2= 1;
public static final int TYPE_COUNT = 2;

//类型的数值不能大于TYPE_COUNT 
//类型的数值不能大于TYPE_COUNT 
//类型的数值不能大于TYPE_COUNT 
//这个是最重要的代码 ,ListView根据这个返回值判断是不是有缓存视图
//即getView()方法的 convertView是不是为null
public int getItemViewType(int position) {
        if ("0".equals(datas.get(position).geType())) {
            return TYPE_1;// 类型1 
        } else if ("1".equals(datas.get(position).getType())) {
            return TYPE_2;// 类型2
        } else {
            return 100;
        }
    }
    public int getViewTypeCount() {
        return TYPE_COUNT;
    }
//补充一点>>>>>>> 我有一个疑问,就是他用getItemType()去判断有木有这个缓存视图的是怎么实现的,最开始又没有这两个类型的视图,怎么去判断!
//实际上,重写两个方法之后,getView方法中
//会自动的将原本只有一屏数据list集合中
//再加上TYPE_COUNT个数的视图,这里是再多存放了两个视图,用于之后的复用,
public View getView(int position, View convertView, ViewGroup parent) {
    //两个视图
    View view_1 = null;
    View view_2 = null;
    Person  p = datas.get(position); //获取相应的数据

    currentType = getItemViewType(position);//重点代码

    if (currentType == TYPE_1) {

        ViewHolder_1 holder_1 = null; //view_1的holder
        if (convertView == null) {
            holder_1 = new ViewHolder_1();

            view_1 = LayoutInflater.from(mContext).
            inflate(R.layout.view_1, null); //加载视图View_1

            //对holder_1 初始化

            view_1.setTag(holder_1); //缓存holder_1
            convertView = view_1; //将convertView赋值
        } else {
            holder_1= (ViewHolder_1) convertView.getTag();
        }
        //各种对ViewHolder的控件进行赋值

    } else if (currentType == TYPE_2) {
        ViewHolder_2 holer_2 = null;
        if (convertView == null) {
            holer_2 = new ViewHolder_2 ();

            view_2 = LayoutInflater.from(mContext).
            inflate(R.layout.view_2, null); //加载视图2
            //对holer_2 初始化
            view_2.setTag(holer_2);
            convertView = view_2; //给convertView赋值
        } else {
            holer_2= (ViewHolder_2) convertView.getTag();
        }

        //各种对ViewHolder_2的控件进行赋值
    }
    return convertView; //返回视图
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值