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 ...
随机推荐
- 《精通Linux内核必会的75个绝技》知识杂记
http://www.ibm.com/developerworks/cn/linux/l-cn-utrace/ utrace是为运行态的进程提供trace和debug支持. utrace能做如下事情: ...
- CSS魔法堂:盒子模型简介
本文讨论的是块级盒子(Block-level box)的盒子模型(Box Model) 一.W3C标准的盒子模型 二.IE盒子模型 三.两种模型的区别 W3C标准盒子模型: 外盒模型 元素空间宽度 ...
- 三分 --- CSU 1548: Design road
Design road Problem's Link: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1548 Mean: 目的:从(0,0)到 ...
- 【JS复习笔记】07 复习感想
好吧,其实<JavaScript语言精粹>后面还简单介绍了代码风格,优美特性,以及包含的毒瘤.糟粕. 但我很快就看完了,发现其实都在前面讲过了,所以就不写了. 至今为止已经算是把JavaS ...
- 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress
[源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...
- 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop
[源码下载] 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop 作者:weba ...
- 解决死锁SQL
USE [master]GO/****** Object: StoredProcedure [dbo].[p_lockinfo] Script Date: 04/03/2014 15:12:40 ** ...
- 使用layout_weight设置控件占屏幕百分比
水平LinearLayout中如果A,B两个控件都是layout_weight="1",那么控件在水平方向占比为A的layout_width+1/2空闲空间,B的layout_wi ...
- Powerbuilder编写身份证校验码
public function boolean of_calc_cardid_verifycode (string as_cardid, ref string as_verifycode); /* 计 ...
- ahjesus ubuntu10.4安装ruby2.1.1
sudo apt-get install python-software-properties sudo apt-add-repository ppa:brightbox/ruby-ng sudo a ...