美文网首页
XTTreeTableView多级列表

XTTreeTableView多级列表

作者: 齐小天_Liu | 来源:发表于2017-03-24 11:56 被阅读343次

    在之前做的一个项目中,有一个功能需求是要将递归的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

    相关文章

      网友评论

          本文标题:XTTreeTableView多级列表

          本文链接:https://www.haomeiwen.com/subject/zsoxottx.html