XTTreeTableView多级列表

2017-03-24  本文已影响343人  齐小天_Liu

在之前做的一个项目中,有一个功能需求是要将递归的json数据,以多级列表的形式展示,并能随意展开,收回。在实现该功能的时候遇到的最大的问题就是对数据的解析,以及数据之间的层级关系的处理。最近想到这个功能,当时是受到某个开源项目的启发,现在自己重新梳理一下思路,加深一下记忆。

一、数据的处理

首先首先说一下对数据的处理。由于从服务器拿到的数据,是递归json数据,而且每个列表中的层级都不确定,有的只有一层、两侧数据,而有的却是多层数据,那这样的数据我们该怎么转换成模型呢?!我的解决方法,用个不太恰当的词形容叫“以牙还牙”,既然你用递归返回数据,那么,我也用同样的方法处理数据。下面看一下具体的实现demo:

1、从服务器上拿下来的数据大概是这个样子的:

@{@"list": @[@{@"name": @"first",@"id": @1,
                    @"subList":@[@{@"name": @"second",@"id": @2},
                                             @{@"name": @"second",@"id": @2}]},
               @{@"name": @"first",@"id": @1,
                   @"subList": @[@{@"name": @"second",@"id": @2,
                                             @"subList": @[@{@"name": @"third",@"id": @3},
                                                                      @{@"name": @"third",@"id": @3}]},
                                             @{@"name": @"second",@"id": @2,
                                             @"subList": @[@{@"name": @"third",@"id": @3},
                                                                       @{@"name": @"third",@"id": @3}]}]},
                  @{@"name": @"first",@"id": @1,
                                             @"subList": @[@{@"name": @"second",@"id": @2},
                                                                       @{@"name": @"second",@"id": @2}]}]};

2、那么我们要怎么把数据字典转换成Model呢,首先先定义Model的属性和方法:

@interface ListModel : NSObject
@property(nonatomic,copy)NSString *name;
//@property(nonatomic,copy)NSString *nameId;
@property(nonatomic,copy)NSNumber *nameId;
@property(nonatomic,copy)NSArray<ListModel *>*subList;//子列表(注:子列表中可能还有子列表)
@property(nonatomic,assign)BOOL isExpand;//是否展开的标记
@property(nonatomic,weak)ListModel *superModel;//父类Model
@property(nonatomic,assign)int level;//深度,即Model所在列表的级数
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)listModelWithDict:(NSDictionary *)dict;
@end

3、接下来才是重点,下面我们来实现initWithDict方法,在该方法中,我们将会对递归数据进行处理,将数据转换成递归模型:

至此,对于数据的处理基本完成,当抓住重点之后,其实对于数据的处理思路还是很明显的。

二、封装tableView

1、首先我们先声明XTTreeTableView的初始化私有方法:

/**
创建XTTreeTableView的方法
@param frame tableView的位置
@param data tableView待展示的数据源
@return XTTreeTableView
*/
-(instancetype)initWithFrame:(CGRect)frame withData:(NSArray *)data;

接下来我们来看在XTTreeTableView.m中方法的实现。

2、我们现来声明XTTreeTableView的私有属性:

@property (nonatomic , strong) NSArray *data;//传递过来已经组织好的数据(最外层的Model)
@property (nonatomic , strong) NSMutableArray *tempData;//用于存储数据源(需要展示的数据)

3、下面我们来实现XTTreeTableView的创建方法:

- (instancetype)initWithFrame:(CGRect)frame withData:(NSArray *)data
{
    self = [super initWithFrame:frame style:UITableViewStyleGrouped];
    if (self) {
        self.dataSource = self;
        self.delegate = self;
        _data = data;
        _tempData = [NSMutableArray arrayWithArray:data];
}
    return self;
}

初始化tableView之后,我们还要实现tableView的数据源方法:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.tempData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CELL_ID = @"XTTree";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELL_ID];
    }
    ListModel *model = self.tempData[indexPath.row];
    cell.textLabel.text = model.name;
    return cell;
}

4、下面我们来实现tableView的代理方法,这是重中之重,前面所以的准备都是为了这一功能。他实现思路是:当我们点击某一行cell时,首先我们拿到这一行对应的Model,判断该Model中的subList是否有subModel,如果有,则可以展开、收回,对是否展开属性取相反值parentModel.isExpand=!parentModel.isExpand;没有则不能展开、收回。

而对于可以展开、收回的,如果parentModel.isExpand=YES,即要展开列表,我们将subModel从subList中取出,插入到需要展示的数据源self.tempData中的相应位置,然后在tableView中的相应位置插入cell;

if (parentModel.isExpand) {//如果展开
    for (int i = 0; i < parentModel.subList.count; i ++) {
        ListModel *subModel = parentModel.subList[i];
        [self.tempData insertObject:subModel atIndex:endPosition];
        endPosition ++;
    }
    expand = YES;
}

如果'parentModel.isExpand=NO',即收回列表,我们将subList中的subModel从self.tempData中删除,然后将想应的cell从tableView中delete。

- (NSInteger)removeAllModelsAtSupModel:(ListModel *)supModel
{
    NSInteger startPosition = [self.tempData indexOfObject:supModel];
    CGFloat count;
    for (int i = 0; i < supModel.subList.count; i ++) {
        ListModel *model = supModel.subList[i];
        count ++;
        if (model.isExpand) {
            count += model.subList.count;
            model.isExpand = NO;
        }
    }
    NSInteger endPosition = startPosition + count + 1;//supModel.subList.count + 1;
    [self.tempData removeObjectsInRange:NSMakeRange(startPosition+1, count)];
    return endPosition;
}

总结:

第一次写简书,为了加深自己的学习,有什么不足之处,还望大家多多指正。Demo:XTTreeTableView

上一篇下一篇

猜你喜欢

热点阅读