代码地址如下:
http://www.demodashi.com/demo/15006.html

效果预览

一、需求

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多级列表

代码地址如下:
http://www.demodashi.com/demo/15006.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

iOS TableView多级列表的更多相关文章

  1. Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等

    目录 一.概述 二.效果展示 三.定制表头 1.重写数据源 2.重写QHeaderView 四.设置属性 五.相关文章 原文链接:Qt实现表格控件-支持多级列表头.多级行表头.单元格合并.字体设置等 ...

  2. Android UI 之实现多级列表TreeView

    所谓TreeView就是在Windows中常见的多级列表树,在Android中系统只默认提供了ListView和ExpandableListView两种列表,最多只支持到二级列表的实现,所以如果想要实 ...

  3. [转]彻底征服Word 2007标题多级列表

    [转]彻底征服Word 2007标题多级列表 用Word编写文档的人都知道,一篇长文档一般是需要分章节来划分段落的.在Word中也有对应的工具来完成这项任务,这就是多级列表.然而绝大多数使用Micro ...

  4. word 多级列表设置

    今天写论文碰到了这个问题, 希望能出现这样的效果: 第一章 1.1 1.2 第二章 2.1 2.2 ...... 为了达到这个效果,晕死了.因为我的标题不是普通的默认标题一标题二   比如同济一标题 ...

  5. WORD2007多级列表

    转自玄鸟翩翩 http://hi.baidu.com/shine_yen http://hi.baidu.com/shine_yen/item/01ff2255043bc1aeacc85722 用Wo ...

  6. Word2010编号列表&多级列表

    1.引用场景         对于一份标准.漂亮的word文档,编号列表和多级列表的设置时必不可少的,正因为有它们,文档看起来才更专业,使用起来才更加的方便.如下面截图一般,这是十分常见的多级列表设置 ...

  7. ios tableview 上加 textfiled

    ios tableview 上加 textfiled 首先附上我项目中用曾经用到的几张图  并说明一下我的用法: 图1: 图2: 图3: 心在你我说一下  我当初的实现 方法 ,希望能给你们一些  启 ...

  8. iOS 6分享列表——UIActivityViewController详解

    iOS 6分享列表——UIActivityViewController详解 2013-06-03 01:42:33     发表评论 在iOS 6之后提供了一个分享列表视图,它通过UIActivity ...

  9. 多级列表——ExpandableListView

    ExpandableListView控件提供的是一个多级列表(一般是两级),我们先来看一下效果图,如图4.18所示为头部列表,单击其中的每一项下面会显示第二级列表,如图4.19所示. 从图4.18和图 ...

随机推荐

  1. Verilog 加法器和减法器(7)

    在计算机中浮点数 表示通常采用IEEE754规定的格式,具体参考以下文章. https://www.cnblogs.com/mikewolf2002/p/10095995.html 下面我们在Veri ...

  2. go语言之进阶篇单向channel特点

    1.单向channel特点 package main //"fmt" func main() { //创建一个channel, 双向的 ch := make(chan int) / ...

  3. 【流处理】Kafka Stream-Spark Streaming-Storm流式计算框架比较选型

    Kafka Stream-Spark Streaming-Storm流式计算框架比较选型 elasticsearch-head Elasticsearch-sql client NLPchina/el ...

  4. ElasticSearch5.X—模糊查询和获取所有索引字段

    最近在做一个分布式数据存储的项目,需要用到ElastciSearch加速数据查询,其中部分功能需要进行模糊查询和统计索引库中已经建立的索引字段,网上查阅了很多资料,最终把这两个问题解决了,不容易!下面 ...

  5. GPUImage简单滤镜使用(一)

    今天来学习一下一个简单滤镜使用的流程,通过调节亮度滤镜来了解.先将GPUImage库导入到项目中,引入头文件"GPUImage.h"   一.创建亮度滤镜对象    GPUImag ...

  6. 虚拟机Linux下解决ping时出现 unknown host问题

    在虚拟机中使用CentOS6.5时,ping www.baidu.com出现报错信息:“ping: unknown hostwww.baidu.com”,虚拟机和物理机网络连接是NAT方式,物理机访问 ...

  7. 程序员的福音,AI可以自动修复bug了!

    人工智能完全学会自己编程,可能说起来还有一种科幻感,但 AI 帮程序员找 bug 这件事,已经达到了不错的水平. 北京大学.微软亚洲研究院和中国电子科技大学就一起尝试着让 AI 找 bug.微软亚洲研 ...

  8. .Net Framework System.Collections 集合类

    本文内容 集合类 性能 最近复习了一下集合,C# 关于集合的类蛮多,但我除了 List 那几个经常用之外,其他的用得还真不多(只在小范围使用),但其实,每个集合类都各有自己适用的场景,功能也很强大.尤 ...

  9. python 微信企业号

    python 微信企业号 准备,如果没有微信企业号,可以先申请体验号记下CorpID和Secret(获取Token用) 发送消息首先可以在微信的开发者中心,查看接口文档 下面就是python代码:1. ...

  10. python 导出mongoDB数据中的数据

    import pymongo,urllibimport sysimport timeimport datetimereload(sys)sys.setdefaultencoding('utf8')fr ...