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

  

  这个我也问了同事以及开发群里的朋友,居然都没得到最优的实现方式的回答,看来这种复杂列表的需求还是比较少的,我自己也走了一些弯路,把我几个实现的方式整理下,希望对于还不了解的朋友有所帮助。

实现方式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多种布局的列表实现的更多相关文章

  1. Android开发之ListView添加多种布局效果演示

    在这个案例中展示的新闻列表,使用到ListView控件,然后在适配器中添加多种布局效果,这里通过重写BaseAdapter类中的 getViewType()和getItemViewType()来做判断 ...

  2. Android ListView Adapter的getItemViewType和getViewTypeCount多种布局

     <Android ListView Adapter的getItemViewType和getViewTypeCount多种布局> 在Android的ListView中.假设在一个Lis ...

  3. Android RecycleView多种布局实现(工厂模式)

    RecycleView是个很常用的控件,很多APP中都可以看到它的身影,同时它也是个很难用的控件,主要就难在多种布局的实现. 在<第一行代码—Android>这本书里边有个RecycleV ...

  4. Android BottomSheet:List列表或Grid网格展示(3)

     Android BottomSheet:List列表或Grid网格展示(3) BottomSheet可以显示多种样式的底部弹出面板风格,比如常见的List列表样式或者Grid网格样式,以一个例子 ...

  5. 让我们创建屏幕- Android UI布局和控件

    下载LifeCycleTest.zip - 278.9 KB 下载ViewAndLayoutLessons_-_Base.zip - 1.2 MB 下载ViewAndLayoutLessons_-_C ...

  6. Android线性布局(Linear Layout)

    Android线性布局(Linear Layout) LinearLayout是一个view组(view group),其包含的所有子view都以一个方向排列,垂直或是水平方向.我们能够用androi ...

  7. Android用户界面布局(layouts)

    Android用户界面布局(layouts) 备注:view理解为视图 一个布局定义了用户界面的可视结构,比如activity的UI或是APP widget的UI,我们可以用下面两种方式来声明布局: ...

  8. Android:布局合集

    本文归纳Android布局中所用到的知识点,网络上的教程说得太细化,而对于前端来说,下面的归纳最适合不过了. Android五大布局: LinearLayout 线性布局 Relativelayout ...

  9. Android帧布局(Frame Layout)

    Android帧布局(Frame Layout) FrameLayout是最简单的一个布局管理器.FrameLayout为每个加入其中的组件创建一个空白区域(一帧),这些组件根据layout_grav ...

随机推荐

  1. iOS 8 界面设计 PSD 模板(iPhone 6),免费下载

    在 iOS 8 发布不久,Teehan & Lax 就发布了 iOS 8(iPhone6)用户界面的 PSD 模板.该网站分享众多 PSD 模板素材,这些精美的 PSD 界面模板在制作界面原型 ...

  2. JS基础---->js中ajax的使用

    AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术.今天我们就简单的学习一下ajax的使用及过程. ajax的使用 先贴出大致的代码,是请求本地的一个servlet,返回json格 ...

  3. VM不能连入局域网

    如果选了Host-only,那么虚拟机与跑虚拟机的宿主就无法连通了. 可以选用Bridged模式,那么虚拟机与跑虚拟机的主机连通了

  4. BABOK2主要概要输入输出图

  5. Mysql学习笔记(七)查(补充)

    PS:五一还是要学习...虽然有点苦逼..但是路是自己选的,那么自己就要坚持的走下去... 学习内容: 1.数据库查找的补充... 查找涉及的东西比较多,在上一个章节没有完全介绍...我们还是以pet ...

  6. sitemesh学习笔记(1)

    最近在学习web开发的时候,发现很多的页面都存在同样的导航栏,登陆栏,js,jQuery等等相同的元素.这样就感觉开发变得好臃肿啊,并且,有时候改一个元素,就要把所有包含这个元素的页面全部重新码一遍, ...

  7. 在VS中使用TinyFox调试OWIN应用(转)

    在很早一段时间之前,我曾经写过一篇关于Katana的使用方法的文章<如何安装并简单的使用OwinHost——Katana>,上面就有介绍如何在VS中调试使用Katana作为Host的App ...

  8. 请求参数到表述层的类型转换——Struts2

    一.简介 说明:HTTP 协议传输数据没有类型的概念,在服务器端是通过 request.getParameter().request.getParameterValue() 方法得到请求参数为 Str ...

  9. 面向对象的JavaScript(一)命名空间

    在小项目中对于JavaScript使用,只要写几个function就行了.但在大型项目中,尤其是在开发追求良好的用户体验的网站中,如SNS,就会用到大量的JavaScrpt,有时JavaScript的 ...

  10. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...