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

  

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

实现方式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. 《精通Linux内核必会的75个绝技》知识杂记

    http://www.ibm.com/developerworks/cn/linux/l-cn-utrace/ utrace是为运行态的进程提供trace和debug支持. utrace能做如下事情: ...

  2. CSS魔法堂:盒子模型简介

    本文讨论的是块级盒子(Block-level box)的盒子模型(Box Model) 一.W3C标准的盒子模型   二.IE盒子模型 三.两种模型的区别 W3C标准盒子模型: 外盒模型 元素空间宽度 ...

  3. 三分 --- CSU 1548: Design road

    Design road Problem's Link:   http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1548 Mean: 目的:从(0,0)到 ...

  4. 【JS复习笔记】07 复习感想

    好吧,其实<JavaScript语言精粹>后面还简单介绍了代码风格,优美特性,以及包含的毒瘤.糟粕. 但我很快就看完了,发现其实都在前面讲过了,所以就不写了. 至今为止已经算是把JavaS ...

  5. 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress

    [源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...

  6. 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop

    [源码下载] 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop 作者:weba ...

  7. 解决死锁SQL

    USE [master]GO/****** Object: StoredProcedure [dbo].[p_lockinfo] Script Date: 04/03/2014 15:12:40 ** ...

  8. 使用layout_weight设置控件占屏幕百分比

    水平LinearLayout中如果A,B两个控件都是layout_weight="1",那么控件在水平方向占比为A的layout_width+1/2空闲空间,B的layout_wi ...

  9. Powerbuilder编写身份证校验码

    public function boolean of_calc_cardid_verifycode (string as_cardid, ref string as_verifycode); /* 计 ...

  10. ahjesus ubuntu10.4安装ruby2.1.1

    sudo apt-get install python-software-properties sudo apt-add-repository ppa:brightbox/ruby-ng sudo a ...