项目中我们会遇到大量的树状列表,每个页面需要的数据和风格样式也不尽相同,新增一个页面就会进行大量的代码复制。所以我们自己封装一个树状列表控件,适配所有页面。
包含功能如下:
- 多级列表
- 折叠/展开
- 单选多选
- 一键展开 / 折叠 N 级列表
- 一键勾选 / 取消勾选
使用
-
创建视图控制器继承我们的 LLTreeTableViewController
-
遵守协议 LLTreeTableViewControllerParentClassDelegate
实现对应的协议方法并赋予数据
- (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];
}];
}
- 数据创建
主要思路:将表格中的每一行需要显示的数据,封装成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];
}