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 ...
随机推荐
- jQuery对Table一个字段排序
最近做一个机票的系统,要对航班信息进行排序,所以整理了一下,把排序的方法写下来. 首先table的结构大概如下 最后显示的样式为 首先在每一个tr上加一个自定义属性:data-sort-field-f ...
- [C#高级编程].NET体系结构
本章内容: 编译和运行面向 .NET的代码 MSIL的优点 值类型和引用类型 数据类型化 理解错误处理和特性 程序集..NET基类和命名空间 本章主要介绍一些概念,内容不多. C#是专门为Micros ...
- sprint2 项目部署+展示
项目展示网址: http://160q49b998.51mypc.cn/ (注:所有用户密码都为123456,校内断网时访问不了)
- ADO.NET常用对象的基础概念强化
1.Command对象 1.1 ExcuteNonquery---执行非查询语句,返回受影响的行数,在新增,删除,修改的时候,如果我们要返回结果集那么就不能使用它了: 1.2 ExcuteScalar ...
- C#设计模式——访问者模式(Visitor Pattern)
一.概述由于需求的改变,某些类常常需要增加新的功能,但由于种种原因这些类层次必须保持稳定,不允许开发人员随意修改.对此,访问者模式可以在不更改类层次结构的前提下透明的为各个类动态添加新的功能.二.访问 ...
- js用正则表达式验证用户和密码的安全性,生成随机验证码
制作了一个表单,表单验证用户.密码.随机验证码 html页面
- 不可或缺 Windows Native (5) - C 语言: 数组
[源码下载] 不可或缺 Windows Native (5) - C 语言: 数组 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 数组 示例cArray.h #ifn ...
- 外表cms,内在wiki的系统anwiki
比较完整面向对象的语法格式, 外表cms,内在wiki的系统 http://enanocms.org/features 比较老,php4的语法
- 小白学Linux(二)--命令行基本操作
安装完Ubuntu后,进入系统,呈现在眼前的是Ubuntu的界面,跟windows的差不太多.一般操作系统包含GUI和CLI.GUI就是我们现在看到的,也是windows常用的直接用拖拽,点击等操作对 ...
- Ubuntu配置任意版本的apt-get镜像
我们知道,迄今为止,Ubuntu已有多个发行版,如11.04.11.10,以至于现在最新的16.*.而我们平常通过apt-get来安装软件,如果OS版本不同,那么镜像源的配置就不同,否则就会出现找不到 ...