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和图 ...
随机推荐
- quantum theory
the principles of quantum mechanics by p.a.m.dirac.
- lync2013 错误: 已为不同的传输层安全性(TLS)目标找到类型为“McxInternal”且完全限定的域名(FQDN)为
最近 练习安装lync2013 在发布拓扑结构时遇到如下错误: lync 错误: 已为不同的传输层安全性(TLS)目标找到类型为“McxInternal”且完全限定的域名(FQDN)为“lync.co ...
- 全景分割panopticapi使用
文件解析 参考github:https://github.com/cocodataset/panopticapi 输入图像:
- java正则校验,密码必须由字母和数字组成
一个匹配数字和字母密码的正则表达式 2011 年 12 月 14 日 | Filed under: 正则表达式 and tagged with: 密码 , 正则表达式 , 零宽断言 一个用户注册功能的 ...
- uva 10712 - Count the Numbers(数位dp)
题目链接:uva 10712 - Count the Numbers 题目大意:给出n,a.b.问说在a到b之间有多少个n. 解题思路:数位dp.dp[i][j][x][y]表示第i位为j的时候.x是 ...
- android 微信听筒无声
Dual talk项目sim卡插在卡2时.微信听筒无声: 第三方APP在听筒接听语音时会固定去设audio_mode为incall,而不会去管以下是sim1还是sim2在位. 而speechdrive ...
- QuickXDev插件自己主动升级后player no exist
昨晚上QuickXDev插件执行还ok,今天打开电脑启动sublime text2后.右键run with player提示player no exist watermark/2/text/aHR ...
- Laravel SQL 查询语句集锦
1.从数据表中取得单一数据列 $user= DB::table('users')->where('name','John')->first(); 2.检索表中的所有行 复制代码代码如下: ...
- GB2312码表
GB2312码表 code +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F A1A0 . . · ˉ ˇ ¨ " 々 — - | … ‘ ’ ...
- SuperMap iDesktop之导入数据
SuperMap作为一个平台软件有自己的数据格式,现要将ESRI的SHP数据导入到SuperMap的udb数据库中,可以完成导入,但也不得不说几点问题. 下面是ArcGIS中批量导入SHP的操作界面. ...