iOS 多级列表的实现

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
查看查看194 回复回复1 收藏收藏 分享淘帖 转播转播 分享分享 微信
查看: 194|回复: 1
收起左侧

iOS 多级列表的实现

[复制链接]
1起来 发表于 2016-9-18 09:37:03 | 显示全部楼层 |阅读模式
快来登录
获取优质的苹果资讯内容
收藏热门的iOS等技术干货
拷贝下载Swift Demo源代码
订阅梳理好了的知识点专辑

在项目开发中,层级列表经常遇到,简单点的二级列表利用UITableView的Header就可以实现,再简单点的三级列表通过对Cell高度进行调整也可以实现三级列表的效果。但遇到多级列表,尤其是层次不明的动态列表就比较麻烦了。




1、原理

层级列表和树形结构比较类似,不过不是二叉树,而是多叉树。每个节点只需要拥有指向父节点和子节点的两个指针,就能形成一颗树。我们将多级列表中每一级对象看作一个node,node拥有两个属性,分别为父节点和子节点的ID。

每棵树有个一个虚拟的root节点,它的ID为rootID,所有节点中凡是父节点ID为rootID的便是第一级,对应树结构中的depth(深度)。这样每一个node对象就都拥有了parentID和childrenID, childrenID为node对象的ID。

我们可以通过rootID查出第一级node,再根据第一级node的childrenID查出下一级,依次类推,确定所有节点的父子关系。同时也可以确定叶子节点和第一级节点,也可称为根节点。




2、效果图



2.1、一般多级列表

iOS 多级列表的实现 1

iOS 多级列表的实现 - 敏捷大拇指 - iOS 多级列表的实现 1

一般多级列表



2.2、记录节点历史状态的列表

iOS 多级列表的实现 2

iOS 多级列表的实现 - 敏捷大拇指 - iOS 多级列表的实现 2

记录节点历史状态




3、思路

  • 首先根据rootID获取所有第一级节点,并放入UITableView的数据源dataSourceArr中,展示初始化列表;
  • 展开:点击节点cell,根据childrenID查找下一级nodes,并插入到dataSourceArr 中currentNode的后面,刷新展示;
  • 收拢:点击以打开节点cell,从dataSourceArr的CurrentIndex+1开始,如果该节点的level小于currentNode的level,则移除node,否则停止刷新列表。
  • 点击cell为叶子节点则不响应展开或收拢操作,并把节点信息通过返回。


dataSourceArr中是这样的一种符合树层级结构的顺序:

iOS 多级列表的实现 3

iOS 多级列表的实现 - 敏捷大拇指 - iOS 多级列表的实现 3

dataSourceArr中顺序




4、定义节点对象

iOS 多级列表的实现 4

iOS 多级列表的实现 - 敏捷大拇指 - iOS 多级列表的实现 4

节点对象




5、遇到问题



5.1、局部刷新的问题

每次展开或收拢以后刷新列表,一开始采用

[Objective-C] 纯文本查看 复制代码
 - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation


但会导致节目有整体闪烁的效果,体验不好。最后考虑采用局部刷新insertRowsAtIndexPaths和deleteRowsAtIndexPaths。

但在刷新中会报错

[Swift] 纯文本查看 复制代码
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 2 from section 0 which only contains 2 rows before the update'


推测原因是current Cell在刷新时的numberOfRowsInSection和刷新insert or del的cell时numberOfRowsInSection不一致导致。然后尝试current cell和其他cell分别刷新,完美刷新。

[Objective-C] 纯文本查看 复制代码
    [_reloadArray removeAllObjects];
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

    if (currentNode.isExpand) {
        //expand
        [self expandNodesForParentID:currentNode.childrenID insertIndex:indexPath.row];
        [tableView insertRowsAtIndexPaths:_reloadArray withRowAnimation:UITableViewRowAnimationNone];
    }else{
        //fold
        [self foldNodesForLevel:currentNode.level currentIndex:indexPath.row];
         [tableView deleteRowsAtIndexPaths:_reloadArray withRowAnimation:UITableViewRowAnimationNone];
    }




5.2、怎么保存节点历史状态

当文件级层比较多时,有时希望能关掉层级后再打开时还能保留子层级的打开状态。我们可以会给每一个node一个是否展开的属性,当fold时只修改currentNode的expand属性,expand时对子节点序isexpand=YES的进行遍历插入。

[Objective-C] 纯文本查看 复制代码
//expand
- (NSUInteger)expandNodesForParentID:(NSString*)parentID insertIndex:(NSUInteger)insertIndex{

    for (int i = 0 ; i<_nodes.count;i++) {
        YKNodeModel *node = _nodes[i];
        if ([node.parentID isEqualToString:parentID]) {
            if (!self.isPreservation) {
                node.expand = NO;
            }
            insertIndex++;
            [_tempNodes insertObject:node atIndex:insertIndex];
            [_reloadArray addObject:[NSIndexPath indexPathForRow:insertIndex inSection:0]];//need reload nodes

            if (node.isExpand) {
               insertIndex = [self expandNodesForParentID:node.childrenID insertIndex:insertIndex];
            }
        }
    }

    return insertIndex;
}





6、下载

demo地址:https://github.com/YangKa/YKMutableLevelTableView.git




作者:好个秋先生

都看到这里了,就把这篇资料推荐给您的好朋友吧,让他们也感受一下。

回帖是一种美德,也是对楼主发帖的尊重和支持。

*声明:敏捷大拇指是全球最大的Swift开发者社区、苹果粉丝家园、智能移动门户,所载内容仅限于传递更多最新信息,并不意味赞同其观点或证实其描述;内容仅供参考,并非绝对正确的建议。本站不对上述信息的真实性、合法性、完整性做出保证;转载请注明来源并加上本站链接,敏捷大拇指将保留所有法律权益。如有疑问或建议,邮件至marketing@swifthumb.com

*联系:微信公众平台:“swifthumb” / 腾讯微博:@swifthumb / 新浪微博:@swifthumb / 官方QQ一群:343549891(满) / 官方QQ二群:245285613 ,需要报上用户名才会被同意进群,请先注册敏捷大拇指

嗯,不错!期待更多好内容,支持一把:
支持敏捷大拇指,用支付宝支付10.24元 支持敏捷大拇指,用微信支付10.24元

评分

参与人数 1金钱 +10 贡献 +10 专家分 +10 收起 理由
Anewczs + 10 + 10 + 10 32个赞!专家给力!

查看全部评分

手表哥 发表于 2016-9-20 13:11:58 | 显示全部楼层
这套算法用Swift实现一次呗
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

做任务,领红包。
我要发帖

分享扩散

都看到这里了,就把这资料推荐给您的好朋友吧,让他们也感受一下。
您的每一位朋友访问此永久链接后,您都将获得相应的金钱积分奖励
热门推荐

合作伙伴

Swift小苹果

  • 北京治世天下科技有限公司
  • ©2014-2016 敏捷大拇指
  • 京ICP备14029482号
  • Powered by Discuz! X3.1 Licensed
  • swifthumb Wechat Code
  •   
快速回复 返回顶部 返回列表