android多种布局的列表实现
最近有一个列表效果,需要一个列表有多种布局,最终效果如下:

这个我也问了同事以及开发群里的朋友,居然都没得到最优的实现方式的回答,看来这种复杂列表的需求还是比较少的,我自己也走了一些弯路,把我几个实现的方式整理下,希望对于还不了解的朋友有所帮助。
实现方式1:(每次getView时重新inflate itemView,convertView没有复用,性能低,运行没问题)
private class MyAdapter extends BaseAdapter{
private List<Object> datas = Collections.EMPTY_LIST;
public void setDatas(List<Object> datas) {
if(datas == null){
datas = Collections.EMPTY_LIST;
}
this.datas = datas;
notifyDataSetChanged();
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Object data = getItem(position);
if(data instanceof Folder){
FolderViewHolder holder = null;
if(convertView != null && convertView.getTag() instanceof FolderViewHolder){
//View与数据类型一致
holder = (FolderViewHolder) convertView.getTag();
}else{
convertView = mInflater.inflate(R.layout.listitem1, null);
holder = new FolderViewHolder(convertView);
convertView.setTag(holder);
}
holder.setData((Folder)data);
}else{
FileViewHolder holder = null;
if(convertView != null && convertView.getTag() instanceof FileViewHolder){
//View与数据类型一致
holder = (FileViewHolder) convertView.getTag();
}else{
convertView = mInflater.inflate(R.layout.listitem2, null);
holder = new FileViewHolder(convertView);
convertView.setTag(holder);
}
holder.setData((File)data);
}
return convertView;
}
}
private class FolderViewHolder{
public TextView tvName;
public FolderViewHolder(View itemView){
tvName = (TextView) itemView.findViewById(R.id.tvName);
}
public void setData(Folder data) {
tvName.setText(data.name);
}
}
private class FileViewHolder{
public TextView tvName;
public FileViewHolder(View itemView){
tvName = (TextView) itemView.findViewById(R.id.tvName);
}
public void setData(File data) {
tvName.setText(data.name);
}
}
实现方式2:(因为方式1不断inflate view,影响性能,于是考虑是否能尽可能重用已经inflate的view,于是添加了一个缓存,不过实际测试快速滑动或切换数据会显示异常,应该是AbsListView#RecycleBin缓存的原因,具体原因我后面理清了再添加,看别人的代码最痛苦了。。。)
private class MyAdapter extends BaseAdapter{
private List<View> folderViewCaches = new ArrayList<View>(5);
private List<View> fileViewCaches = new ArrayList<View>(5);
private List<Object> datas = Collections.EMPTY_LIST;
public void setDatas(List<Object> datas) {
if(datas == null){
datas = Collections.EMPTY_LIST;
}
this.datas = datas;
notifyDataSetChanged();
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Object data = getItem(position);
if(data instanceof Folder){
//文件夹,应该返回R.layout.listitem1对应的View
FolderViewHolder holder = null;
if(convertView != null && convertView.getTag() instanceof FolderViewHolder){
//View与数据类型一致
holder = (FolderViewHolder) convertView.getTag();
}else{
if(convertView != null){
//缓存到文件列表
fileViewCaches.add(convertView);
convertView = null;
}
//从缓存里面取已从ListView移除的缓存(注释掉此部分代码显示正常)
if(!folderViewCaches.isEmpty()){
for(View cache : folderViewCaches){
if(cache.getParent() == null){
//缓存的View已从listView里面移除
convertView = cache;
holder = (FolderViewHolder) convertView.getTag();
folderViewCaches.remove(cache);
break;
}
}
}
//还是没有,重新inflate
if(convertView == null){
convertView = mInflater.inflate(R.layout.listitem1, null);
holder = new FolderViewHolder(convertView);
convertView.setTag(holder);
}
}
holder.setData((Folder) data);
}else{
//文件,应该返回R.layout.listitem2对应的View
FileViewHolder holder = null;
if(convertView != null && convertView.getTag() instanceof FileViewHolder){
//View与数据类型一致
holder = (FileViewHolder) convertView.getTag();
}else{
if(convertView != null){
//缓存到文件夹列表
folderViewCaches.add(convertView);
convertView = null;
}
//从缓存里面取已从ListView移除的缓存(注释掉此部分代码显示正常)
if(!fileViewCaches.isEmpty()){
for(View cache : fileViewCaches){
if(cache.getParent() == null){
//缓存的View已从listView里面移除
convertView = cache;
holder = (FileViewHolder) convertView.getTag();
fileViewCaches.remove(cache);
break;
}
}
}
//还是没有,重新inflate
if(convertView == null){
convertView = mInflater.inflate(R.layout.listitem2, null);
holder = new FileViewHolder(convertView);
convertView.setTag(holder);
}
}
holder.setData((File) data);
}
return convertView;
}
}
实现方式3:(最佳实现,运行正常)
后面仔细阅读ListView相关源码,才发现Adapter本身就支持不同的布局了,而且AbsListView#RecycleBin也支持不同类型的布局的缓存策略,RecycleBin.mViewTypeCount标示有多少种View类型。
我们需要做的就是重写Adapter的下面3个方法:
1.getViewTypeCount:
/**
* 有多少种不同布局的View
*/
@Override
public int getViewTypeCount() {
return 2;
}
2.getItemViewType
/**
* 相应position对应的View类型
*/
@Override
public int getItemViewType(int position) {
if(getItem(position) instanceof Folder){
return TYPE_FOLDER;
}else{
return TYPE_FILE;
}
}
3.getView,通过判断对应position的类型,返回相应类型的view:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Object data = getItem(position); if(data instanceof Folder){
//TYPE_FOLDER,文件夹,应该返回R.layout.listitem1对应的View
FolderViewHolder holder = null;
if(convertView != null){
holder = (FolderViewHolder) convertView.getTag();
}else{
convertView = mInflater.inflate(R.layout.listitem1, null);
holder = new FolderViewHolder(convertView);
convertView.setTag(holder);
} holder.setData((Folder) data); }else{
//TYPE_FILE,文件,应该返回R.layout.listitem2对应的View
FileViewHolder holder = null;
if(convertView != null){
holder = (FileViewHolder) convertView.getTag();
}else{
convertView = mInflater.inflate(R.layout.listitem2, null);
holder = new FileViewHolder(convertView);
convertView.setTag(holder);
} holder.setData((File) data);
} return convertView;
}
此demo的github源码地址:
https://github.com/John-Chen/BlogSamples/tree/master/MultipleListTest
apk下载地址:
https://github.com/John-Chen/BlogSamples/blob/master/MultipleListTest/MultipleListTest.apk
如果写的有问题的地方,欢迎指教!
android多种布局的列表实现的更多相关文章
- Android开发之ListView添加多种布局效果演示
在这个案例中展示的新闻列表,使用到ListView控件,然后在适配器中添加多种布局效果,这里通过重写BaseAdapter类中的 getViewType()和getItemViewType()来做判断 ...
- Android ListView Adapter的getItemViewType和getViewTypeCount多种布局
<Android ListView Adapter的getItemViewType和getViewTypeCount多种布局> 在Android的ListView中.假设在一个Lis ...
- Android RecycleView多种布局实现(工厂模式)
RecycleView是个很常用的控件,很多APP中都可以看到它的身影,同时它也是个很难用的控件,主要就难在多种布局的实现. 在<第一行代码—Android>这本书里边有个RecycleV ...
- Android BottomSheet:List列表或Grid网格展示(3)
Android BottomSheet:List列表或Grid网格展示(3) BottomSheet可以显示多种样式的底部弹出面板风格,比如常见的List列表样式或者Grid网格样式,以一个例子 ...
- 让我们创建屏幕- Android UI布局和控件
下载LifeCycleTest.zip - 278.9 KB 下载ViewAndLayoutLessons_-_Base.zip - 1.2 MB 下载ViewAndLayoutLessons_-_C ...
- Android线性布局(Linear Layout)
Android线性布局(Linear Layout) LinearLayout是一个view组(view group),其包含的所有子view都以一个方向排列,垂直或是水平方向.我们能够用androi ...
- Android用户界面布局(layouts)
Android用户界面布局(layouts) 备注:view理解为视图 一个布局定义了用户界面的可视结构,比如activity的UI或是APP widget的UI,我们可以用下面两种方式来声明布局: ...
- Android:布局合集
本文归纳Android布局中所用到的知识点,网络上的教程说得太细化,而对于前端来说,下面的归纳最适合不过了. Android五大布局: LinearLayout 线性布局 Relativelayout ...
- Android帧布局(Frame Layout)
Android帧布局(Frame Layout) FrameLayout是最简单的一个布局管理器.FrameLayout为每个加入其中的组件创建一个空白区域(一帧),这些组件根据layout_grav ...
随机推荐
- 【leetcode】3 SUM
3 SUM 原题: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? F ...
- HT图形组件设计之道(一)
HT for Web简称HT提供了涵盖通用组件.2D拓扑图形组件以及3D引擎的一站式解决方案,正如Hightopo官网所表达的我们希望提供:Everything you need to create ...
- Node.js爬虫数据抓取乱码问题总结
一.非UTF-8页面处理 1.背景 windows-1251编码 比如俄语网站:https://vk.com/cciinniikk 可耻地发现是这种编码 所有这里主要说的是 Windows-1251( ...
- ADO.NET常用对象的基础概念强化
1.Command对象 1.1 ExcuteNonquery---执行非查询语句,返回受影响的行数,在新增,删除,修改的时候,如果我们要返回结果集那么就不能使用它了: 1.2 ExcuteScalar ...
- 组合数学 - 母函数的运用 + 模板 --- hdu : 2082
找单词 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- 重构第25天 引入契约设计(Introduce Design By Contract checks)
理解:本文中的”引入契约式设计”是指我们应该对应该对输入和输出进行验证,以确保系统不会出现我们所想象不到的异常和得不到我们想要的结果. 详解:契约式设计规定方法应该对输入和输出进行验证,这样你便可以保 ...
- MVC bundle(包扎)CSS或是JS文件
以前写asp.net网页时,会在<head>节点中引用很多样式文件或是javascript文件,如下图左大括号的引用语句. 现在在MVC应用程序中,可以使用使用Bundle来捆一起, 在S ...
- node.js实现CURL功能
PHP中的CURL功能很好实现,直接四五行代码封装一下就OK了.node.js中如何实现CURL的功能呢,下面详细介绍. 这里需要用到request这个库,所以先安装此包: npm install r ...
- out 和 ref 参数修饰符
整理自MSDN out: out 关键字通过引用传递参数.这与 ref 关键字相似,只不过 ref 要求在传递之前初始化变量.若要使用 out 参数,方法定义和调用方法均必须显式使用 out 关键字. ...
- 浅谈ImageList
ImageList组件用了很久,但是一直不太清楚它的实现原理,今天专门特意花了时间倒腾了下,终于弄明白了!于是在这里和大家分享下! 在设计页面中打卡工具箱-组件 找到ImageList组件,将它直接拖 ...