您的位置:首页 > 其它

ListView 使用多布局的方法和简单的原理分析

2016-03-26 15:44 441 查看
很多时候我们需要用到一个listview使用多个布局的情况,例如聊天的界面



这是从网上下载的图片,仅供参考。

实现:

下面来分析一下如何实现图中的效果:

如果要滑动的话,可以使用scrollView或者是listview, 但是scrollView 对于内存上无法实现view的复用,所以说不是一个好的方案。

使用listview就要使用多个布局文件,这个在android在baseadapter中已经为我们开放了非常方便的途径:

1、重写 int getItemViewType(int position)

在这个方法中返回我们来区别不同文件的tag,例如左边的聊天放回0, 右边的聊天放回1;

2、重写int getViewTypeCount

在这个方法中放回布局的个数,具体返回的大小,一会再做非常重要的解释。

先上传整体的伪代码:

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public class TestAdapter extends BaseAdapter {

private Context context;
private List<ChatMessage> data;

public TestAdapter(Context context, List<ChatMessage> data) {
this.context = context;
this.data = data;
}

@Override
public int getItemViewType(int position) {
// 左边的聊天放回0 ,右边的聊天返回1
return data.get(position).getType();
}

@Override
public int getViewTypeCount() {
return 2;
}

@Override
public int getCount() {
return data.size();
}

@Override
public Object getItem(int arg0) {
return data.get(arg0);
}

@Override
public long getItemId(int arg0) {
return arg0;
}

@Override
public View getView(int position, View convertView, ViewGroup arg2) {
// 获取当前位置的type, 0 为左边聊天, 1为右边的聊天
int type = getItemViewType(position);
switch (type) {
case 0:
// 引用左边聊天的布局
convertView = LayoutInflater.from(context).inflate(..., null);
// 展示内容的操作
...
break;
case 1:
// 引用右边聊天的布局
convertView = LayoutInflater.from(context).inflate(..., null);
// 展示内容的操作
...
break;
default:
break;
}
return convertView;
}

private class ChatMessage {
int type;

public int getType() {
return type;
}
}

}


分析

代码非常的简单,其实还可以进行Holder这样的优化,这里只是简单说明一下使用的方法,就不具体优化了。

非常初级的api使用方法,完全没有什么难度,但是有一个问题一直困扰我很久:getViewTypeCount()这个方法中返回的这个值到底有什么用?

有的人会说:这里返回的是不同布局的个数。

经过我的测试,发现只要返回的值比 int getItemViewType(int position)这个方法中返回的最大值大就没有问题。例如上面的代码中,我们返回的type最大值是1,所以只要返回比1大的所有值都没问题。那么这种解释就说不通了。

今天又重新看了一下listview的复用机制才忽然意识到这个值到底起到了什么作用:

先简要说明listview的循环复用机制,一个listview至多为自己的item缓存 当前屏幕展示的个数 + 2, 滑动的时候把移除屏幕的item添加到缓冲区,回到屏幕时从缓冲区获取一个item来展示,这样就实现了item的复用,大大降低了内存的开销。具体的分析资料可以在郭霖老师和张鸿洋老师的博客中看到。

那么在listview多个布局的时候会发生怎么样的变化呢?

原理是还是一样的,唯一的不同就是我们之前重写的两个方法的返回了不一样的值。

1、 int getItemViewType(int position)

这个方法帮助listview区分不同的布局文件,缓冲布局文件的是一个数组,返回的int值就是缓冲区不同布局文件的下标,0 就代表 放在数组第一个位置, 1就代表放在第二个位置,需要复用的时候直接根据返回的int下标去获取需要的item, 如果不重写这个方法,那么位置肯定是唯一的,也就只有一个布局文件,我们可以猜测默认值是0;

2、int getViewTypeCount

在这个方法中返回的值就很重要了,他实际上是缓冲区的长度,所以这个值就必须要比getItemViewType(int position)返回的最大值要大,如果小的话,就会报数组越界异常,所以开头的问题就得到解决了。我们也可以猜测这个默认值返回的是1。

个人还是建议发挥恰当的值,例如 我们需要两个布局文件一个类型0, 一个类型100, 那么我们至少要设置长度是100, 中间的98个位置全是空的,作为一个开发者而言,是不允许这种站着茅坑不拉屎的行为发生的。

到这里这篇博客就结束了,希望这篇文章可以帮助大家去理解listview的实现原理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: