树状结构LLTreeTableViewController使用

项目中我们会遇到大量的树状列表,每个页面需要的数据和风格样式也不尽相同,新增一个页面就会进行大量的代码复制。所以我们自己封装一个树状列表控件,适配所有页面。

包含功能如下:

  • 多级列表
  • 折叠/展开
  • 单选多选
  • 一键展开 / 折叠 N 级列表
  • 一键勾选 / 取消勾选
使用
  1. 创建视图控制器继承我们的 LLTreeTableViewController


    image.png
  2. 遵守协议 LLTreeTableViewControllerParentClassDelegate
    实现对应的协议方法并赋予数据


    image.png
- (void)loadData {
    
    MBProgressHUD *toastHUD = [[MBProgressHUD alloc] initWithView:self.navigationController ? self.navigationController.view : self.view];
    toastHUD.backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
    toastHUD.backgroundView.color = [UIColor colorWithWhite:0.f alpha:.2f];
    toastHUD.label.text = @"加载中";
    toastHUD.removeFromSuperViewOnHide = YES;
    toastHUD.userInteractionEnabled = YES;
    [toastHUD showAnimated:YES];
    if (self.navigationController) {
        [self.navigationController.view addSubview:toastHUD];
    }
    else{
        [self.view addSubview:toastHUD];
    }

    
    
    
    WeakSelf(self);
    StrongSelf(weakSelf);
    LinPropertyScopeReleaseParamsModel *param = [LinPropertyScopeReleaseParamsModel new];
    param.neighNo = kPropertyCurrentNeighMd.neighNo;
    param.applyNo = self.applyNo;
    param.applyType = self.applyType;
    param.applyNoFrom = self.applyNoFrom;
    
    [LinPropertyHttpCloudUtils requestScopeReleaseTreeWithModel:param success:^(id  _Nullable task, LinIOTBaseResponseModel * _Nullable response, NSInteger result) {
        
        NSArray *treeModelArray = [LinScopeReleaseTreeModel objectArrayWithDictArray:response.params];
        
        strongSelf.manager = [strongSelf getTreeDataWithTreeModel:treeModelArray];

        [toastHUD hideAnimated:YES];
        
    } failure:^(id  _Nullable task, NSError * _Nullable error, NSInteger result, NSString * _Nonnull message) {
        
        strongSelf.manager = [strongSelf getTreeDataWithTreeModel:@[]];
        
        [toastHUD hideAnimated:YES];
    }];
    
}
  1. 数据创建
    主要思路:将表格中的每一行需要显示的数据,封装成item模型,存放在数组当中,然后再将数组数据初始化给LLTreeTableManager类即可。
- (LLTreeTableManager *)getManagerOfCraft {

    // 获取数据并创建树形结构
    NSData *JSONData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Resource" ofType:@"json"]];
    NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingAllowFragments error:nil];

    NSMutableSet *items = [NSMutableSet set];


    [dataArray enumerateObjectsUsingBlock:^(NSDictionary *data, NSUInteger idx, BOOL * _Nonnull stop) {
        LLTreeItem *item = [[LLTreeItem alloc] initWithName:data[@"name"]
                                                         ID:[NSString stringWithFormat:@"%@", data[@"id"]]
                                                   parentID:[NSString stringWithFormat:@"%@", data[@"pid"]]
                                                    orderNo:[NSString stringWithFormat:@"%lu", (unsigned long)idx]
                                                       type:@"test"
                                                     isLeaf:NO
                                                       data:data];
        [items addObject:item];
    }];

    // ExpandLevel 为 0 全部折叠,为 1 展开一级,以此类推,为 NSIntegerMax 全部展开
    LLTreeTableManager *manager = [[LLTreeTableManager alloc] initWithItems:items andExpandLevel:NSIntegerMax];

    return manager;
}

- (LLTreeTableManager *)getManagerOfCity {

    // 获取数据并创建树形结构
    NSData *JSONData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cityResource" ofType:@"json"]];
    NSArray *provinceArray = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingAllowFragments error:nil];

    NSMutableSet *items = [NSMutableSet set];

    // 1. 遍历省份
    [provinceArray enumerateObjectsUsingBlock:^(NSDictionary *province, NSUInteger idx, BOOL * _Nonnull stop) {

        LLTreeItem *provinceItem = [[LLTreeItem alloc] initWithName:province[@"name"]
                                                                 ID:province[@"code"]
                                                           parentID:nil
                                                            orderNo:[NSString stringWithFormat:@"%lu", (unsigned long)idx]
                                                               type:@"province"
                                                             isLeaf:NO
                                                               data:province];
        [items addObject:provinceItem];

        // 2. 遍历城市
        NSArray *cityArray = province[@"children"];
        [cityArray enumerateObjectsUsingBlock:^(NSDictionary *city, NSUInteger idx, BOOL * _Nonnull stop) {

            LLTreeItem *cityItem = [[LLTreeItem alloc] initWithName:city[@"name"]
                                                                 ID:city[@"code"]
                                                           parentID:provinceItem.ID
                                                            orderNo:[NSString stringWithFormat:@"%lu", (unsigned long)idx]
                                                               type:@"city"
                                                             isLeaf:NO
                                                               data:city];
            [items addObject:cityItem];

            // 3. 遍历区
            NSArray *districtArray = city[@"children"];
            [districtArray enumerateObjectsUsingBlock:^(NSDictionary *district, NSUInteger idx, BOOL * _Nonnull stop) {

                LLTreeItem *districtItem = [[LLTreeItem alloc] initWithName:district[@"name"]
                                                                         ID:district[@"code"]
                                                                   parentID:cityItem.ID
                                                                    orderNo:[NSString stringWithFormat:@"%lu", (unsigned long)idx]
                                                                       type:@"district"
                                                                     isLeaf:YES
                                                                       data:district];
                [items addObject:districtItem];
            }];
        }];
    }];

    // ExpandLevel 为 0 全部折叠,为 1 展开一级,以此类推,为 NSIntegerMax 全部展开
    LLTreeTableManager *manager = [[LLTreeTableManager alloc] initWithItems:items andExpandLevel:0];


    return manager;
}

4.树状结构包含的属性以及方法使用

  • 属性
@property (nonatomic, strong) LLTreeTableManager *manager;

@property (nonatomic, assign) BOOL isShowExpandedAnimation;   // 是否显示展开/折叠动画,默认 YES
@property (nonatomic, assign) BOOL isShowArrowIfNoChildNode;  // 是否没有子节点就不显示箭头,默认 NO
@property (nonatomic, assign) BOOL isShowArrow;               // 是否显示文字前方的箭头图片,默认 YES
@property (nonatomic, assign) BOOL isShowCheck;               // 是否显示文字后方的勾选框,默认 YES
@property (nonatomic, assign) BOOL isSingleCheck;             // 是否是单选,默认 NO
@property (nonatomic, assign) BOOL isCancelSingleCheck;       // 是否单选时再次点击取消选择,默认 NO
@property (nonatomic, assign) BOOL isExpandCheckedNode;       // 是否展开已选择的节点,默认 YES
@property (nonatomic, assign) BOOL isShowLevelColor;          // 是否展示层级颜色,默认 YES
@property (nonatomic, assign) BOOL isShowSearchBar;           // 是否显示搜索框,默认 YES
@property (nonatomic, assign) BOOL isSearchRealTime;          // 是否实时查询,默认 YES

@property (nonatomic, strong) NSArray <NSString *>*checkItemIds;    // 从外部传进来的所选择的 itemIds
@property (nonatomic, strong) NSArray <UIColor *>*levelColorArray;  // 层级颜色,默认一级和二级分别为深灰色和浅灰色
@property (nonatomic, strong) UIColor *normalBackgroundColor;       // 默认背景色,默认为白色
@property (nonatomic, assign) BOOL isEnableEdit; //是否可以编辑 默认可以编辑
  • 属性使用
    self.isShowExpandedAnimation  = YES; //是否显示展开/折叠动画
    self.isShowArrowIfNoChildNode = YES; // 是否没有子节点就不显示箭头,默认 NO
    self.isShowArrow              = YES; // 是否显示文字前方的箭头图片,默认 YES
    self.isShowCheck              = YES; // 是否显示文字后方的勾选框,默认 YES
    self.isSingleCheck            = NO;  // 是否是单选,默认 NO
    self.isCancelSingleCheck      = NO;  // 是否单选时再次点击取消选择,默认 NO
    self.isExpandCheckedNode      = YES; // 是否展开已选择的节点,默认 YES
    self.isShowLevelColor         = NO;  // 是否展示层级颜色,默认 YES
    self.isShowSearchBar          = NO;
    self.isEnableEdit = NO;     //是否可以编辑 默认可以编辑
  • 协议实现
#pragma mark - LLTreeTableViewControllerParentClassDelegate
//数据源
- (void)refreshTableViewController:(LLTreeTableViewController *)tableViewController {
    [self loadData];
}

- (void)tableViewController:(LLTreeTableViewController *)tableViewController checkItems:(NSArray<LLTreeItem *> *)items {
    // 这里加一个隔离带目的是可以在这里做出个性化操作,然后再将数据传出
    if ([self.delegate respondsToSelector:@selector(tableViewController:checkItems:)]) {
        [self.delegate tableViewController:self checkItems:items];
    }
    
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)tableViewController:(LLTreeTableViewController *)tableViewController didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"点击了第 %ld 行", (long)indexPath.row);
}

- (void)tableViewController:(LLTreeTableViewController *)tableViewController didSelectCheckBoxRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"点击了第 %ld 行的 checkbox", (long)indexPath.row);
}
  • 方法
/** 全部勾选/全部取消勾选 */
- (void)checkAllItem:(BOOL)isCheck;
/** 全部展开/全部折叠 */
- (void)expandAllItem:(BOOL)isExpand;
/** 展开/折叠到多少层级 */
- (void)expandItemWithLevel:(NSInteger)expandLevel;
/** 准备提交,调用代理方法 */
- (void)prepareCommit;
/** 获取当前显示的 showItems */
- (NSArray *)getShowItems;
/** 获取所有的 Items */
- (NSArray *)getAllItems;
/** 获取所有勾选的 Items */
- (NSArray *)getCheckItems;
  • 方法的使用
//提交
- (void)commitItemClick {
    [self prepareCommit];
}

//全选
- (void)allCheckItemClick {
    [self checkAllItem:YES];
}

//全部展开
- (void)allExpandItemClick {
    [self expandAllItem:YES];
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容