ListView 使用多布局的方法和简单的原理分析
2016-03-26 15:44
441 查看
很多时候我们需要用到一个listview使用多个布局的情况,例如聊天的界面
![](http://img.blog.csdn.net/20160326144232422)
这是从网上下载的图片,仅供参考。
如果要滑动的话,可以使用scrollView或者是listview, 但是scrollView 对于内存上无法实现view的复用,所以说不是一个好的方案。
使用listview就要使用多个布局文件,这个在android在baseadapter中已经为我们开放了非常方便的途径:
1、重写 int getItemViewType(int position)
在这个方法中返回我们来区别不同文件的tag,例如左边的聊天放回0, 右边的聊天放回1;
2、重写int getViewTypeCount
在这个方法中放回布局的个数,具体返回的大小,一会再做非常重要的解释。
先上传整体的伪代码:
非常初级的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的实现原理。
这是从网上下载的图片,仅供参考。
实现:
下面来分析一下如何实现图中的效果:如果要滑动的话,可以使用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的实现原理。
相关文章推荐
- 网站设计配色笔记(一)
- 博客即简历【转载】
- 20159320《网络攻防实践》第4周教材学习总结
- Swift3.0 多态 、继承 、 强制转换
- git configuration
- tomcat的exploded archive 和packaged archive 有什么区别?
- 避免使用import *
- commons.net FTP 实现断点续传
- BloomFilter
- 关于CSS一些要点
- 原型模式--你的作业写完啦,借我们抄抄吧!
- PAT (Advanced Level) Practise 1105 Spiral Matrix (25)
- Volley初探
- 销售收入科目确定VKOA
- 使用模板类实现List容器&迭代器
- 告诫自己要有目标
- test15
- 进度条
- 【转】WebSocket 是什么原理?为什么可以实现持久连接?
- 最大子数组和01