iOS TableView多级列表
效果预览

一、需求
TableView多级列表:分级展开或合并,逐级获取并展示其子级数据,可以设置最大的层级数,支持多选、单选、取消选择。
二、思路
由需求和示意图可知,这些数据元素之间存在着一对多关系,很符合 数据结构与算法 -- 树形结构 的特征。那么,我们就用树形结构中的结点(Node)来作为存储和关联数据的模型(NodeModel)。
//每个结点信息,采用的是树状结构模型
关于树状结构不了解的可以看看我的这篇文章 https://www.jianshu.com/p/c545c93f2585
@interface SLNodeModel : NSObject
@property (nonatomic, strong) NSString *parentID; // 父结点ID 即当前结点所属的的父结点ID
@property (nonatomic, strong) NSString *childrenID; //子结点ID 即当前结点的ID
@property (nonatomic, strong) NSString *name; //结点名字
@property (nonatomic, assign) int level; // 结点层级 从1开始
@property (nonatomic, assign) BOOL leaf; // 树叶(Leaf) If YES:此结点下边没有结点咯;
@property (nonatomic, assign) BOOL root; // 树根((Root) If YES: parentID = nil
@property (nonatomic, assign) BOOL expand; // 是否展开
@property (nonatomic, assign) BOOL selected; // 是否选中
@end
三、实现
层级状态: 根据传入的层级数来调整层级UI状态。
展开或合并: 通过插入或删除cell的方式来实现。(示例中的数据都是假数据,随机生成的。)
插入和删除的位置以及范围可通过点击的结点的位置、层级、子结点ID(当前结点ID)与子结点的层级或父节点相比较来确定。可以的话,做一下缓存处理,优化不分大小,从点滴做起。
/**
获取并展开父结点的子结点数组 数量随机产生
@param level 父结点的层级
@param indexPath 父结点所在的位置
*/
- (void)expandChildrenNodesLevel:(int)level atIndexPath:(NSIndexPath *)indexPath {
NSMutableArray * insertNodeRows = [NSMutableArray array];
int insertLocation = (int)indexPath.row + 1;
for (int i = 0; i < arc4random()%9; i++) {
SLNodeModel * node = [[SLNodeModel alloc] init];
node.parentID = @"";
node.childrenID = @"";
node.level = level + 1;
node.name = [NSString stringWithFormat:@"第%d级结点",node.level];
node.leaf = (node.level < MaxLevel) ? NO : YES;
node.root = NO;
node.expand = NO;
node.selected = NO;
[self.dataSource insertObject:node atIndex:insertLocation + i];
[insertNodeRows addObject:[NSIndexPath indexPathForRow:insertLocation + i inSection:0]];
}
//插入cell
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithArray:insertNodeRows] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
//更新新插入的元素之后的所有cell的cellIndexPath
NSMutableArray * reloadRows = [NSMutableArray array];
int reloadLocation = insertLocation + (int)insertNodeRows.count;
for (int i = reloadLocation; i < self.dataSource.count; i++) {
[reloadRows addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView reloadRowsAtIndexPaths:reloadRows withRowAnimation:UITableViewRowAnimationNone];
}
/**
获取并隐藏父结点的子结点数组
@param level 父结点的层级
@param indexPath 父结点所在的位置
*/
- (void)hiddenChildrenNodesLevel:(int)level atIndexPath:(NSIndexPath *)indexPath {
NSMutableArray * deleteNodeRows = [NSMutableArray array];
int length = 0;
int deleteLocation = (int)indexPath.row + 1;
for (int i = deleteLocation; i < self.dataSource.count; i++) {
SLNodeModel * node = self.dataSource[i];
if (node.level > level) {
[deleteNodeRows addObject:[NSIndexPath indexPathForRow:i inSection:0]];
length++;
}else{
break;
}
}
[self.dataSource removeObjectsInRange:NSMakeRange(deleteLocation, length)];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:deleteNodeRows withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
//更新删除的元素之后的所有cell的cellIndexPath
NSMutableArray * reloadRows = [NSMutableArray array];
int reloadLocation = deleteLocation;
for (int i = reloadLocation; i < self.dataSource.count; i++) {
[reloadRows addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView reloadRowsAtIndexPaths:reloadRows withRowAnimation:UITableViewRowAnimationNone];
}
选中: 会更新当前结点下所有子结点的选中状态。
选中的位置以及范围可通过点击的结点的位置、层级、子结点ID(当前结点ID)与子结点的层级或父节点相比较来确定。可以的话,做一下缓存处理,优化不分大小,从点滴做起。
/**
更新当前结点下所有子节点的选中状态
@param level 选中的结点层级
@param selected 是否选中
@param indexPath 选中的结点位置
*/
- (void)selectedChildrenNodes:(int)level selected:(BOOL)selected atIndexPath:(NSIndexPath *)indexPath {
NSMutableArray * selectedNodeRows = [NSMutableArray array];
int deleteLocation = (int)indexPath.row + 1;
for (int i = deleteLocation; i < self.dataSource.count; i++) {
SLNodeModel * node = self.dataSource[i];
if (node.level > level) {
node.selected = selected;
[selectedNodeRows addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}else{
break;
}
}
[self.tableView reloadRowsAtIndexPaths:selectedNodeRows withRowAnimation:UITableViewRowAnimationNone];
}
四、项目结构

iOS TableView多级列表
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
iOS TableView多级列表的更多相关文章
- Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等
目录 一.概述 二.效果展示 三.定制表头 1.重写数据源 2.重写QHeaderView 四.设置属性 五.相关文章 原文链接:Qt实现表格控件-支持多级列表头.多级行表头.单元格合并.字体设置等 ...
- Android UI 之实现多级列表TreeView
所谓TreeView就是在Windows中常见的多级列表树,在Android中系统只默认提供了ListView和ExpandableListView两种列表,最多只支持到二级列表的实现,所以如果想要实 ...
- [转]彻底征服Word 2007标题多级列表
[转]彻底征服Word 2007标题多级列表 用Word编写文档的人都知道,一篇长文档一般是需要分章节来划分段落的.在Word中也有对应的工具来完成这项任务,这就是多级列表.然而绝大多数使用Micro ...
- word 多级列表设置
今天写论文碰到了这个问题, 希望能出现这样的效果: 第一章 1.1 1.2 第二章 2.1 2.2 ...... 为了达到这个效果,晕死了.因为我的标题不是普通的默认标题一标题二 比如同济一标题 ...
- WORD2007多级列表
转自玄鸟翩翩 http://hi.baidu.com/shine_yen http://hi.baidu.com/shine_yen/item/01ff2255043bc1aeacc85722 用Wo ...
- Word2010编号列表&多级列表
1.引用场景 对于一份标准.漂亮的word文档,编号列表和多级列表的设置时必不可少的,正因为有它们,文档看起来才更专业,使用起来才更加的方便.如下面截图一般,这是十分常见的多级列表设置 ...
- ios tableview 上加 textfiled
ios tableview 上加 textfiled 首先附上我项目中用曾经用到的几张图 并说明一下我的用法: 图1: 图2: 图3: 心在你我说一下 我当初的实现 方法 ,希望能给你们一些 启 ...
- iOS 6分享列表——UIActivityViewController详解
iOS 6分享列表——UIActivityViewController详解 2013-06-03 01:42:33 发表评论 在iOS 6之后提供了一个分享列表视图,它通过UIActivity ...
- 多级列表——ExpandableListView
ExpandableListView控件提供的是一个多级列表(一般是两级),我们先来看一下效果图,如图4.18所示为头部列表,单击其中的每一项下面会显示第二级列表,如图4.19所示. 从图4.18和图 ...
随机推荐
- 在IIS上SSL的部署和启动SSL安全【转】
在这次的项目中遇见了这个问题,之前我并懂了不了多少,只对了SSL和HTTPS理论了解.但并不知道在实际中如何运行.经过自己在网上查阅一番,最后靠自己解决了这个问题,现在在这里和大家分享一下.如果写的有 ...
- Mongodb的windows服务安装和卸载
不用 InstallUtil.exe,直接用mongod.exe做就可以: 安装:mongod --dbpath "C:\mongodb\db" --logpath "C ...
- 算法: 实现LRU缓存,读取、写入O(1)实现
这题应该见的不少了,写写记录一下. 实现该功能分析: (1) O(1) 时间完成查找,那除了 hash 别无选择. (2) LRU 最近最少使用算法,为了方便数据的淘汰.需要对最近访问的数据放未访问数 ...
- iOS开发--知识点总结
1 .全局变量,变量名前加下划线.和系统一致. 2 . nil指针为空 @“”字符串为空 (内容为空) == 判断内存地址 基本变量 对于一些基本类型 可以使用==来判断, ...
- Scramble String leetcode java
题目: Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty subs ...
- Spring Boot集成MyBatis开发Web项目
1.Maven构建Spring Boot 创建Maven Web工程,引入spring-boot-starter-parent依赖 <project xmlns="http://mav ...
- Java-JUC(十):线程按序交替执行
问题: 有a.b.c三个线程,使得它们按照abc依次执行10次. 实现: package com.dx.juc.test; import java.util.concurrent.locks.Cond ...
- LynxFly科研小四轴横空出世,开源,F4,WIFI --(转)
首先是一大堆的感谢,太多人的帮助,感谢不完了----首先要说明,这个PCB工程的出现要感谢论坛上的台湾大哥 john800422 开源了自己的飞控板的工程文件,我这样的没啥基础的小弟们才能学会如何制板 ...
- sqrt函数的实现
原文:http://blog.csdn.net/legend050709/article/details/39394381 sqrt算法实现: (一)int sqrt1(int n);求取整数x的平方 ...
- Python操作记录
1.写入中文出错,需要执行 reload(sys) sys.setdefaultencoding('utf8') 2.json.dump中文写入为\xxxx ensure_ascii=False