项目中需要使用一个多层级关系的ListView,问了下需求,回答是无限级。。。好吧,参考了网上的各种资源,似乎对无限级这种都没有很好的解决方案,特别是在后台给我的数据仅仅告诉我上一级的名称,大致就是{“私有属性”,”上一级菜单名称”},偶尔看到一个开发人员的一个提示,所谓的展开就是增加item,关闭就是删除item,顿时有了一个极其笨的办法。既然是最没有技术含量的,所以这里也会有一些问题,最严重的问题就是——性能低下,如果处理数量大的,还是另辟蹊径吧。
闲话少说,开始正文:
1.数据bean类 MenuData.class

    private String name; // 本级菜单的名字private String text; // 服务器传来要展示的数据,可以是任意数据形式private String top_menu; // 上级菜单名称,无论返回上下级菜单关系,原理是一样的private boolean isNext; // 是否有下一级菜单private boolean isOpen; // 菜单是否展开private int level; // 所在层级//setter getter...

这边后台太弱,我这边的层级和是否有下一级菜单,都是我自己定义和计算出来的,如果后台强大,完全没必要这个步骤。

黑体加粗强调下,得到的数据先一律将isOpen设为false,因为都是关闭的,这个步骤我是在获取数据的地方设置的
2.整理服务器得来的数据

// 整理从服务器获取的数据private void initData(List<MenuData> list) {// 得到第一级菜单List<MenuData> menuList = new ArrayList<>();menuList.clear(); // 习惯问题,清一下,就跟刷新一样for (MenuData data : list) {// 我这边第一级菜单服务器返回的上级菜单是"null",对,没看错是字符串"null"if ("null".equals(data.getTop_menu())) {// 设置层级data.setLevel(1);// 寻找是否有下级菜单for (MenuData data1 : list) {if (data.getName().equals(data1.getTop_menu())) {// 存在即说明有data.setNext(true);break;} else {// 一直没有那就是没有咯data.setNext(false);}}// 把一级菜单都加到菜单列表中menuList.add(data);}}// 这里创建一个菜单map,key是菜单的名字,value是该菜单名字下的下一级菜单集合menuMap = new HashMap<>();menuMap.put("null", menuList);// 差不多就可以可以感受到没有技术含量的代码了,两次for循环完了,再来三次for (MenuData data : list) {String name = data.getName();// 一定要在new一次,也就是一个新的对象,而不是clear,不然。。。你试试menuList = new ArrayList<>();for (int j = 0; j < list.size(); j++) {if (name.equals(list.get(j).getTop_menu())) {for (MenuData data1 : list) {if (data.getName().equals(data1.getTop_menu())) {data.setNext(true);break;} else {data.setNext(false);}}menuList.add(list.get(j));}}menuMap.put(name, menuList);}// 此处的mList是与ListViw绑定的list,也就是负责数据更新的,此处是让页面进入即显示第一级菜单mList.clear();mList.addAll(menuMap.get("null"));mAdapter.notifyDataSetChanged();}

看到没有,如果后台够强大,直接返回层级和是否有下级菜单,将省下很多事情,什么你看到我mList,mAdapter都没定义,别闹,这个你应该会啊,来给你完整代码

    mListView = (ListView) v.findViewById(R.id.list_view);mList = new ArrayList<>();mAdapter = new MenuAdapter(mContext, mList);mListView.setAdapter(mAdapter);

3.adapter中的处理
什么叫史上最没有技术含量,那就是,没有什么特别要求,你以前怎么写的,现在怎么写就行了,完全一样。好吧,我有一点小要求,比如缩进,比如打开和关闭的图标不同,背景颜色要不一样。给关键代码吧

// 背景颜色,因为我的是白色文字,所以这四种颜色比较搭,各位自行选择啊
private int[] colors = {0xFF000000, 0xFF0033CC, 0xFF01CC00, 0xFFFF3300};... 此处省略各种写adapter就要重复的代码MenuData data = mList.get(position);vh.tx.setText(data.getText());vh.name.setText(data.getName());// 把图标进行缩进,因为我的图标是在最前面,自行选择哪个控件缩进vh.icon.setPadding((data.getLevel() - 1) * 8, 8, 8, 8);vh.layout.setBackgroundColor(colors[data.getLevel() % 4]);// 判断是否有下级菜单if (!data.isNext()) {// 没有下级菜单显示圆圈vh.icon.setImageResource(R.mipmap.knowledgetree_leaf);} else if (data.isOpen()) {// 有下级菜单,且为展开状态vh.icon.setImageResource(R.mipmap.knowledgetree_rootexpanded);} else {// 有下级菜单,且为关闭状态vh.icon.setImageResource(R.mipmap.knowledgetree_rootunexpanded);}

我比较大方,送你三张图片了


还有什么事要做了?最重要的,展开和关闭状态要实现啊,不然要写这个干吗啊。。。
各位要想按图标进行展开和关闭了,就在adapter里面设置,嗯,会吧?我是整个item点击有效,所以我就是在页面的类里面写的了。
如果要在adapter里面写,给个思路吧,设置监听的时候,把position带上就ok了。
下面那个是我在这个项目中基本类似需求的代码,我就不在这说了。

class Click implements View.OnClickListener {int position;public Click(int position) {this.position = position;}@Overridepublic void onClick(View v) {Data data = mList.get(position);switch (v.getId()) {case R.id.btn1:break;case R.id.btn2:break;}}}

4.数据更新

 private class ItemClick implements android.widget.AdapterView.OnItemClickListener {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {MenuData menuData = mList.get(position);// 因为要对数据更新,所以先把数据暂存下来List<MenuData> tempList = new ArrayList<>();tempList.addAll(mList);if (!menuData.isOpen() && menuData.isNext()) {// 记录该菜单是展开状态menuData.setOpen(true);mList.clear();// 又到体现最没技术含量的时刻到了,简单点说就是,把点击项的前面原样放入list,把点击的那项下一级菜单加进去,再把原来的后部分数据加进去for (int tempI = 0; tempI <= position; tempI++) {mList.add(tempList.get(tempI));}// 获得点击的下级菜单,并插入for (MenuData data : menuMap.get(menuData.getName())) {// 服务器没有返回层级,所以自己计算层级,很容易理解data.setLevel(menuData.getLevel() + 1);// 这里的作用是再怎么没有技术含量也要适当考虑性能,计算目前展开的最大层级,方便下面的关闭菜单,下面会讲到if (menuData.getLevel() + 1 > maxOpen) {maxOpen = menuData.getLevel() + 1;}mList.add(data);}for (int tempI = position + 1; tempI < tempList.size(); tempI++) {mList.add(tempList.get(tempI));}// 这里就要进行关闭菜单了} else if (menuData.isOpen() && menuData.isNext()) {menuData.setOpen(false);String delName = menuData.getName();// 这里要注意,与展开不同,展开只要插入下一级菜单,而关闭是要将下一级及以下包含的各级全部移除,这里知道我上面要定义展开最大层级的作用了吧for (int i = 0; i < tempList.size(); i++) {MenuData delData = tempList.get(i);String delTopName = delData.getTop_menu();for (int tempI = menuData.getLevel(); tempI < maxOpen; tempI++) {if (delTopName.equals(delName)) {delData.setOpen(false);mList.remove(delData);} else {for (int j = 0; j < tempList.size(); j++) {if (tempList.get(j).getName().equals(delTopName)) {delTopName = tempList.get(j).getTop_menu();}}}}}}mAdapter.notifyDataSetChanged();}}

因为没有技术含量,所以有点难以理解,主要是要理解核心思想:展开就是增加,关闭就是删除,以上代码就好理解了。

因为这是实际商业项目中的内容,所以我改了一些变量名字,而且不是在开发工具中,是在该博客中写的,所以可能会有误差,希望各位理解核心思想,仅供参考,copy代码极易出错。However,我在周末一定把能用的demo放上。哈哈。。。能copy还是copy吧。

遇到的问题:这只能说是一个替代方案,这里的无限级虽然可以实现,但是效率很低,其次,如果考虑每一级都有缩进的话,会发现item占满全屏了,那么显示就会很乱,这里就需要左右滑动的效果,我还没有实现,如果有解决方案的希望一起探讨。

附上demo地址
demo地址

打造史上最没有技术含量的多级(无限级)ListView相关推荐

  1. 玩转直播+短视频 京东打造“史上最简单618”

    疫情之下,直播+短视频成为新时代的"弄潮儿",也成为本届"618"的最大看点之一! 与往年不同,本届"618"购物节,京东在站内站外联动布置 ...

  2. 史上最强技术电信诈骗蔓延!无法防范!只能等死!

    短信抢劫啊 看到一篇文章不错,十分的不错,不错到有些恐怖了,直接就转载过来了! 文章原文 没有办法防范!无法抵挡!没有办法防范! 重要的话说三遍!是真的无法防范!到你头上你就死! 否则我们不会那么着急 ...

  3. 史上最污技术解读...啊哈~“好变态”~~~

    史上最污技术解读 看完妙懂 - 假如 你是个妹纸 假设你是个妹子,你有一位男朋友,于此同时你和另外一位男生暧昧不清,比朋友好,又不是恋人.你随时可以甩了现任男友,另外一位马上就能补上.这是 冷备份 . ...

  4. “婚礼哥”蹿红网络:用巨资打造史上最完美的婚礼征服女明星

    "婚礼哥"蹿红网络:用巨资打造史上最完美的婚礼征服女明星 近日以来,以让所有"北漂爱情不再白漂"以及对当红女明星徐千雅网络示爱"我要做你一生的北京情人 ...

  5. GitHub 标星 44k!史上最全技术面试手册!

    大家好,我是为前端娱乐圈操碎了心的小迷妹,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标. 每天上班必须做的一件事情,就是打开 ...

  6. Android 自定义控件打造史上最简单的侧滑菜单

    侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin ...

  7. 打造史上最小尺寸.Net Core单文件应用程序

    .Net Core支持将应用程序发布成单文件进行部署和分发. 以下示例将Windows应用作为独立的单文件应用程序发布: dotnet publish -r win-x64 -c Release /p ...

  8. [Perl] Python 与 Perl 合并,打造史上最牛语言 Parrot

    本文链接: http://www.php-oa.com/2010/04/01/python-perl-parrot.html 据Perl官方网站的消息,Perl之父Larry Wall和Python之 ...

  9. powerbuilder TriggerEvent 参数_NLP界“威震天”袭来!英伟达1小时83亿参数打造史上最大语言模型...

    [新智元导读]英伟达一举创造了2个壮举!训练出了世界上最大的语言模型--MegatronLM,包含83亿参数,比BERT大24倍,比GPT-2大5.6倍:还打破了实时对话AI的记录,仅耗时53分钟即可 ...

最新文章

  1. ContentResolver.query()—buildQueryString()
  2. 介绍一款开源的类Excel电子表格软件
  3. 《网络维护》MAC地址
  4. 宁波大学2013 计算机应用基础 高级c语言程序 练习册答案,2020年宁波大学计算机应用技术考研真题试卷及试题答案,计算机系统基础考研试题下载...
  5. 数据类型之字符串练习
  6. 一个机器学习博士的忠告
  7. linux监控nmon和analyser的使用
  8. 网络安全:图片防盗链的实现原理
  9. 关于spring boot多张表建立外健的讨论
  10. Linux 7.x 防火墙端口
  11. 物联网VSWiFi 两强争霸还是携手并进?
  12. 网络常用协议 SSH、SSL
  13. Fmask算法——影像云检测算法
  14. stream常用操作
  15. 360修复高危漏洞可以修复吗_大理石刮痕可以修复吗?如何修复?
  16. windows抓包工具——Fiddler配置及使用、手机抓包(iPhone、安卓)
  17. DOTA2怎么清除缓存_第36期 只要一招:彻底重置Windows图标缓存
  18. 智能车入门——跑车前的零碎知识<新手从零做车>
  19. 干货分享:实用/高效/有逼格的Android Studio 常用配置/插件推荐
  20. C# 总结ManualResetEvent与AutoResetEvent【一】

热门文章

  1. 【大疆】1. 无人机测绘区域航拍模式
  2. 基于Springboot的社区开发项目
  3. I2C协议研读(五):7位地址构成详解
  4. ippicv_2017u2_lnx_intel64_20170418.tgz 下载
  5. 土木专业学python有什么用-python在土木
  6. Linphone分析 1_初始化
  7. 欧姆龙e5dc温控器_使用欧姆龙温控器E5DC-RX2ASM-802必读如下
  8. js中soft的用法
  9. 史上最详细的AVL树的实现(万字+动图讲解旋转)
  10. 汇编语言 求数组中的最小偶数