登录 立即注册
金钱:

Code4App-iOS开发-iOS 开源代码库-iOS代码实例搜索-iOS特效示例-iOS代码例子下载-Code4App.com

iOS TableView多级列表

[复制链接]
来自: wsl2ls 分类: iOS精品源码 上传时间: 2019-2-12 09:55:51
Tag:

项目介绍:

TableView多级列表的实现效果预览图

  • 需求

TableView多级列表:分级展开或合并,逐级获取并展示其子级数据,可以设置最大的层级数,支持多选、单选、取消选择。

示例Demo:MultilevelList

  • 思路

由需求和示意图可知,这些数据元素之间存在着一对多关系,很符合 数据结构与算法 -- 树形结构 的特征。那么,我们就用树形结构中的结点(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];
}

选中: 会更新当前结点下所有子结点的选中状态。(示例demo中的效果是只更新当前结点下所有展开的子结点的选中状态,因为子结点的数据是边展开边获取的,合并起来的数据没有保存。)

选中的位置以及范围可通过点击的结点的位置、层级、子结点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];
}

新年快乐

加油

如果需要跟我交流的话:
※ Github: https://github.com/wsl2ls 
※ 简书:https://www.jianshu.com/u/e15d1f644bea 
※ 微信公众号:iOS2679114653
※ QQ:1685527540

相关源码推荐:

我来说两句
*滑动验证:
所有评论(5)
BlueManlove 2019-2-12 10:05:22
帮帮顶顶!!
回复
Yf8546 2019-2-12 10:05:49
code4app确实是个好地方,必须支持~
回复
无限释囚 2019-2-12 10:05:55
膜拜大神~
回复
打个酱油的 2019-2-12 10:06:17
感谢分享,code4app有你更精彩
回复
Wsdtg 2019-2-12 10:06:52
好好 学习了 确实不错
回复
Rf2698 2019-2-12 10:07:00
不错不错,楼主辛苦了。。。
回复
code4app热心网友 2019-2-12 11:37:53
学习学习!
回复
秦强 2019-2-12 14:58:04
感谢分享,Code4App有你更精彩:)
回复
code4app热心网友 2019-2-12 15:20:35
正需要啊,感谢楼主无私分享!
回复
提取码:  下载次数:33 状态:已购或VIP 售价:0(原价:15)金钱 下载权限:初级码农 
778 0 33
联系我们
首页/微信公众账号投稿

帖子代码编辑/版权问题

QQ:435399051,742864542

如何获得代码达人称号?

代码贡献英雄榜
用户名 下载数
通过邮件订阅最新 Code4App 信息
上一条 /4 下一条
联系我们
关闭
合作电话:
13802416937
Email:
435399051@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|Github|申请友链|手机版|Code4App ( 粤ICP备15117877号-1 )

快速回复 返回顶部 返回列表