前言:很久没有更新了,这段时间确实比较忙,也没什么时间去研究一些技术,也很难想出来去研究些什么。iOS发展至今,已经有很多优秀的文档,包含各个方面,自己也经常感慨自己写的,没有别人写的详细,有逻辑。笔者之前很多文章都设置为隐私了,没有再公开,一部分是因为太次,一部分是因为都是些烂大街的东西。
iOS无限分组,也是和朋友交流的时候,碰到的一个需求,目前采用的时候js交互实现的,笔者最近想来,还是用原生的写写试试。
笔者的习惯,所有逻辑注解,都在注释里,大家认真看代码里的注释
废话不多说了,先看下效果图
1,设计思路
1,笔者是对原始数据进行了处理,用一个字典,来存储所有节点数据。
父节点的id作为key,所有父节点相同的数据组合成数组,作为value
所有显示的数据都再重新筛到一个数组里,通过对showArr的处理,来处理数据的展开收起。
2,原始数据介绍
原始数据是一个数组,里面放的是字典,字典的主要key-value为
p_id父节点id
id自身id
live自身层级
看一下原始数据的大致结构,笔者这里只写了五级,各位开发者们,可以自己再加层级测试。
_orgeArr = @[@{@"p_id":@"0",@"id":@"1.0",@"live":@"1"},
@{@"p_id":@"0",@"id":@"2.0",@"live":@"1"},
@{@"p_id":@"0",@"id":@"3.0",@"live":@"1"},
@{@"p_id":@"0",@"id":@"4.0",@"live":@"1"},
@{@"p_id":@"1.0",@"id":@"1.1",@"live":@"2"},
@{@"p_id":@"1.0",@"id":@"1.2",@"live":@"2"},
@{@"p_id":@"2.0",@"id":@"2.1",@"live":@"2"},
@{@"p_id":@"4.0",@"id":@"4.1",@"live":@"2"},
@{@"p_id":@"1.1",@"id":@"1.1.1",@"live":@"3"},
@{@"p_id":@"1.1",@"id":@"1.1.2",@"live":@"3"},
@{@"p_id":@"1.1.1",@"id":@"1.1.1.1",@"live":@"4"},
@{@"p_id":@"1.1.1.1",@"id":@"1.1.1.1.1",@"live":@"5"}];
一生二,二生三,三生万物,阿弥陀佛,各位测试吧。
3,适用场景,大致举例哈
3.1,列表类(比如城市选择)
3.2, 社区评论类(笔者猜想可以用,没有实际实践过)
3.3,自己想去吧 0.0哈哈
2,原始数据处理
_orgeArr = @[@{@"p_id":@"0",@"id":@"1.0",@"live":@"1"},
@{@"p_id":@"0",@"id":@"2.0",@"live":@"1"},
@{@"p_id":@"0",@"id":@"3.0",@"live":@"1"},
@{@"p_id":@"0",@"id":@"4.0",@"live":@"1"},
@{@"p_id":@"1.0",@"id":@"1.1",@"live":@"2"},
@{@"p_id":@"1.0",@"id":@"1.2",@"live":@"2"},
@{@"p_id":@"2.0",@"id":@"2.1",@"live":@"2"},
@{@"p_id":@"4.0",@"id":@"4.1",@"live":@"2"},
@{@"p_id":@"1.1",@"id":@"1.1.1",@"live":@"3"},
@{@"p_id":@"1.1",@"id":@"1.1.2",@"live":@"3"},
@{@"p_id":@"1.1.1",@"id":@"1.1.1.1",@"live":@"4"},
@{@"p_id":@"1.1.1.1",@"id":@"1.1.1.1.1",@"live":@"5"}];
_dataDic = [[NSMutableDictionary alloc] init];
_showArr = [[NSMutableArray alloc] init];
[_orgeArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *p_id = obj[@"p_id"];
// NSString *s_id = obj[@"id"];
NSMutableArray *arr = [[NSMutableArray alloc] init];
if (_dataDic[p_id]) {
[arr addObjectsFromArray:_dataDic[p_id]];
}
[arr addObject:obj];
_dataDic[p_id] = arr;
if (p_id.integerValue == 0) {
[_showArr addObject:obj];
}
}];
3,展开收起状态处理
//判断cell上是否有展开收起按钮
- (void)isShowBtnWithCell:(ListTableViewCell *)cell{
NSInteger btnTag = cell.showBtn.tag;
NSDictionary *dic = _showArr[btnTag];
NSString *s_id = dic[@"id"];
NSArray *arr = _dataDic[s_id];
if (arr && arr.count>0) {
cell.showBtn.hidden = NO;
//如果有展开收起按钮,判断是展开还是收起
if ([_showArr containsObject:arr.firstObject]) {
// [cell.showBtn setTitle:@"收起" forState:UIControlStateNormal];
[cell.showBtn setImage:[UIImage imageNamed:@"delet"] forState:UIControlStateNormal];
}else{
// [cell.showBtn setTitle:@"展开" forState:UIControlStateNormal];
[cell.showBtn setImage:[UIImage imageNamed:@"add"] forState:UIControlStateNormal];
}
}else{
[cell.showBtn setImage:[UIImage imageNamed:@"add"] forState:UIControlStateNormal];
// [cell.showBtn setTitle:@"展开" forState:UIControlStateNormal];
cell.showBtn.hidden = YES;
}
}
4,展开时插入需要展开的数据
//展开收起按钮的点击方法
- (void)showBtnAction:(UIButton *)btn{
//只要此方法走了,就代表有展开收起按钮
NSInteger btnTag = btn.tag;
NSDictionary *dic = _showArr[btnTag];
NSString *s_id = dic[@"id"];
NSArray *arr = _dataDic[s_id];
if ([_showArr containsObject:arr.firstObject]) {
//此时是展开状态,要全部删除次级数据,变为收起状态
//id为次级数据的判断依据
[self delegateShowDataWithDic:dic];
}else{
//此时是收起状态
for (int i = 0; i < arr.count; i ++) {
NSDictionary *obj = arr[i];
if (![_showArr containsObject:obj]) {
[_showArr insertObject:obj atIndex:btnTag+i+1];
}
}
}
[_tableView reloadData];
}
5,收起时,删除所有已展开的数据
//递归删除所有展开的数据
- (void)delegateShowDataWithDic:(NSDictionary *)dic{
//当前节点的id为子节点的p_id
NSString *s_id = dic[@"id"];
NSLog(@"--%@",s_id);
NSArray *arr = _dataDic[s_id];
if (arr == nil) {
for (NSInteger j = _showArr.count-1; j >= 0; j --) {
NSDictionary *delDic = _showArr[j];
//如果子节点的p_id和当前节点的id相同,则表示子节点需要删除
if ([delDic[@"p_id"] isEqualToString:s_id]) {
[_showArr removeObject:delDic];
}
}
}
for (NSInteger i = arr.count-1; i >= 0 ; i --) {
if ([_showArr containsObject:arr[i]]) {
for (NSInteger j = _showArr.count-1; j >= 0; j --) {
NSDictionary *delDic = _showArr[j];
//如果子节点的p_id和当前节点的id相同,则表示子节点需要删除
if ([delDic[@"p_id"] isEqualToString:s_id]) {
[self delegateShowDataWithDic:delDic];
[_showArr removeObjectAtIndex:j];
}
}
}
}
/*此方法有bug,保留是为了参考
if ([_showArr containsObject:arr.firstObject]) {
//说明还有次级数据,继续递归
[self delegateShowDataWithDic:arr.firstObject];
for (NSInteger i = _showArr.count-1; i >= 0; i --) {
NSDictionary *delDic = _showArr[i];
//如果子节点的p_id和当前节点的id相同,则表示子节点需要删除
if ([delDic[@"p_id"] isEqualToString:s_id]) {
[_showArr removeObject:delDic];
}
}
}
*/
}
代码不多,逻辑也不是很复杂,大家仔细想想也就想通了。