打造史上最没有技术含量的多级(无限级)ListView
项目中需要使用一个多层级关系的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相关推荐
- 玩转直播+短视频 京东打造“史上最简单618”
疫情之下,直播+短视频成为新时代的"弄潮儿",也成为本届"618"的最大看点之一! 与往年不同,本届"618"购物节,京东在站内站外联动布置 ...
- 史上最强技术电信诈骗蔓延!无法防范!只能等死!
短信抢劫啊 看到一篇文章不错,十分的不错,不错到有些恐怖了,直接就转载过来了! 文章原文 没有办法防范!无法抵挡!没有办法防范! 重要的话说三遍!是真的无法防范!到你头上你就死! 否则我们不会那么着急 ...
- 史上最污技术解读...啊哈~“好变态”~~~
史上最污技术解读 看完妙懂 - 假如 你是个妹纸 假设你是个妹子,你有一位男朋友,于此同时你和另外一位男生暧昧不清,比朋友好,又不是恋人.你随时可以甩了现任男友,另外一位马上就能补上.这是 冷备份 . ...
- “婚礼哥”蹿红网络:用巨资打造史上最完美的婚礼征服女明星
"婚礼哥"蹿红网络:用巨资打造史上最完美的婚礼征服女明星 近日以来,以让所有"北漂爱情不再白漂"以及对当红女明星徐千雅网络示爱"我要做你一生的北京情人 ...
- GitHub 标星 44k!史上最全技术面试手册!
大家好,我是为前端娱乐圈操碎了心的小迷妹,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标. 每天上班必须做的一件事情,就是打开 ...
- Android 自定义控件打造史上最简单的侧滑菜单
侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin ...
- 打造史上最小尺寸.Net Core单文件应用程序
.Net Core支持将应用程序发布成单文件进行部署和分发. 以下示例将Windows应用作为独立的单文件应用程序发布: dotnet publish -r win-x64 -c Release /p ...
- [Perl] Python 与 Perl 合并,打造史上最牛语言 Parrot
本文链接: http://www.php-oa.com/2010/04/01/python-perl-parrot.html 据Perl官方网站的消息,Perl之父Larry Wall和Python之 ...
- powerbuilder TriggerEvent 参数_NLP界“威震天”袭来!英伟达1小时83亿参数打造史上最大语言模型...
[新智元导读]英伟达一举创造了2个壮举!训练出了世界上最大的语言模型--MegatronLM,包含83亿参数,比BERT大24倍,比GPT-2大5.6倍:还打破了实时对话AI的记录,仅耗时53分钟即可 ...
最新文章
- ContentResolver.query()—buildQueryString()
- 介绍一款开源的类Excel电子表格软件
- 《网络维护》MAC地址
- 宁波大学2013 计算机应用基础 高级c语言程序 练习册答案,2020年宁波大学计算机应用技术考研真题试卷及试题答案,计算机系统基础考研试题下载...
- 数据类型之字符串练习
- 一个机器学习博士的忠告
- linux监控nmon和analyser的使用
- 网络安全:图片防盗链的实现原理
- 关于spring boot多张表建立外健的讨论
- Linux 7.x 防火墙端口
- 物联网VSWiFi 两强争霸还是携手并进?
- 网络常用协议 SSH、SSL
- Fmask算法——影像云检测算法
- stream常用操作
- 360修复高危漏洞可以修复吗_大理石刮痕可以修复吗?如何修复?
- windows抓包工具——Fiddler配置及使用、手机抓包(iPhone、安卓)
- DOTA2怎么清除缓存_第36期 只要一招:彻底重置Windows图标缓存
- 智能车入门——跑车前的零碎知识<新手从零做车>
- 干货分享:实用/高效/有逼格的Android Studio 常用配置/插件推荐
- C# 总结ManualResetEvent与AutoResetEvent【一】
热门文章
- 【大疆】1. 无人机测绘区域航拍模式
- 基于Springboot的社区开发项目
- I2C协议研读(五):7位地址构成详解
- ippicv_2017u2_lnx_intel64_20170418.tgz 下载
- 土木专业学python有什么用-python在土木
- Linphone分析 1_初始化
- 欧姆龙e5dc温控器_使用欧姆龙温控器E5DC-RX2ASM-802必读如下
- js中soft的用法
- 史上最详细的AVL树的实现(万字+动图讲解旋转)
- 汇编语言 求数组中的最小偶数