之前在自己的项目中,遇到了这样一需求,项目里有聊天的功能,需要自己管理好友列表,而且好友是属于有上下级的关系,所有就要做一个树状的UITabelView的结构.
首先说一下大概的思路:
1.根据我自己的项目来说,首先是请求接口,获得联系人列表数据,当然需要根据数据建立数据模型model,这个是我项目里的数据模型:
@interface ObjModel : NSObject
@property (nonatomic,copy)NSString * ID;//这个是该对象上一级的唯一标示ID
@property (nonatomic,copy)NSString * imCode;
@property (nonatomic,copy)NSString * name;
@property (nonatomic,copy)NSString * pId;//这个是该对象的唯一标示ID
@property (nonatomic,copy)NSString * type;//对象所属的类型
@property (nonatomic,copy)NSString * level;//用来标示是树状结构中的哪一级
@property (nonatomic,copy)NSString * isOpened;//这里需要构建模型的时候,将isOpened设置为NO(我是用的KVC给数据模型赋值)
@property (nonatomic,retain)NSMutableArray *subItems;//该对象包含子对象,也就是树状的节点
@end
2.将模型建立好,根据模型来进行分组,整理出我们想要的数据结构,具体的方法,我自己写的很绕,但是没有找到好的循环方法....如下:
#pragma mark --- 对对象进行分组
- (NSMutableArray * )groupWithArray:(NSMutableArray *)array{
NSMutableArray * dataArray = @[].mutableCopy;
for (ObjModel * rootItem in array) {
if ([rootItem.type isEqualToString:@"firstLevel"]) {//首先根据类型找出第一级
rootItem.level = @"0";//第一级的level
rootItem.subItems = @[].mutableCopy;
for (ObjModel * firstItem in array) {
if ([firstItem.type isEqualToString:@"secondLevel"]&&[firstItem.pId isEqualToString:rootItem.ID]) {//根据类别找出第二级,如果该对象的pId和第一级对象的ID一样,那么它是第二级
firstItem.level = @"1";//第二级的level
firstItem.subItems = @[].mutableCopy;
[rootItem.subItems addObject:firstItem];//将第二级加到第一级中
for (ObjModel * thirdItem in array) {
if ([thirdItem.type isEqualToString:@"thirdLevel"]&&[thirdItem.pId isEqualToString:firstItem.ID]) {//同理,找出第三级
thirdItem.level = @"2";
thirdItem.subItems = @[].mutableCopy;
[firstItem.subItems addObject:thirdItem];
}
}
}
}
[dataArray addObject:rootItem];//把第一级加到dataArray中,也就是tableView的数据源中,此时的数据就是包含了树状结构的
}
}
return dataArray;
}
3.数据结构整理好,那么初始化tableView,其中tableView要设置为UITableViewStylePlain的样式,
最终要的地方:要实现这个方法的树状结构,最主要的是要用到tableView的两个方法:
- (void)insertRowsAtIndexPaths:(NSArray*)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;//根据indexPath向局部插入新的数据,刷新局部数据
- (void)deleteRowsAtIndexPaths:(NSArray*)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;//根据indexPath向局部删除数据,刷新局部数据
和- (void)reloadRowsAtIndexPaths:(NSArray*)indexPaths withRowAnimation:(UITableViewRowAnimation)animation很类似
我这里就是利用到了点击tableViewCell,判断点击cell所属对象的isOpened,如果是NO,就调用- (void)insertRowsAtIndexPaths:(NSArray*)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
如果是YES,就调用- (void)reloadRowsAtIndexPaths:(NSArray*)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
具体实现的方法:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
ObjModel * item = self.dataArray[indexPath.row];//得到该cell对应的数据对象
if ([item.isOpened isEqualToString:@"YES"]) {
//这个是树状展开的状态
NSMutableArray * arr = @[].mutableCopy;
arr = [self deleteMenuIndexPaths:item];//让树状收起来的方法
if ([arr count] >0) {
[self.tableView deleteRowsAtIndexPaths: arr withRowAnimation:UITableViewRowAnimationMiddle];
}
}else if([item.isOpened isEqualToString:@"NO"]){
//这个是树状收起来的状态
NSMutableArray * arr = @[].mutableCopy;
arr = [self insertMenuIndexPaths:item]; //让树状展开
if ([arr count] >0) {
[self.tableView insertRowsAtIndexPaths:arr withRowAnimation:UITableViewRowAnimationBottom];
}
}
}
#pragma mark --- insert
- (NSMutableArray *)insertMenuIndexPaths:(ObjModel *)item{
NSMutableArray * array = @[].mutableCopy;
[self.treeItemsToInsert removeAllObjects];//treeItemsToInsert为需要插入的数据模型数组
[self insertMenuObject:item];
array = [self insertIndexsOfMenuObject:self.treeItemsToInsert];
return array;
}
- (void)insertMenuObject:(ObjModel *)item{
if (item == nil) {
return;
}
NSIndexPath * path = [NSIndexPath indexPathForRow:[self.dataArray indexOfObject:item] inSection:0];
for (int i = 0; i < item.subItems.count; i ++) {
ObjModel * childItem = item.subItems[i];
[self.dataArray insertObject:childItem atIndex:path.row + i + 1];
[self.treeItemsToInsert addObject:childItem];
item.isOpened = @"YES";
}
}
- (NSMutableArray *)insertIndexsOfMenuObject:(NSMutableArray *)array{
NSMutableArray * tempArray = @[].mutableCopy;
for (ObjModel * item in array) {
NSIndexPath * path = [NSIndexPath indexPathForRow:[self.dataArray indexOfObject:item] inSection:0];
[tempArray addObject:path];
}
return tempArray;
}
#pragma mark --- delete
- (NSMutableArray *)deleteMenuIndexPaths:(ObjModel *)item{
NSMutableArray * array = @[].mutableCopy;
[self.treeItemsToRemove removeAllObjects];
[self deleteMenuObject:item];
array = [self deleteIndexsOfMenuObject:self.treeItemsToRemove];
return array;
}
- (void)deleteMenuObject:(ObjModel *)item{
if (item == nil)
{
return ;
}
for (int i = 0; i < item.subItems.count && [item.isOpened isEqualToString:@"YES"]; i ++) {
ObjModel * childItem = item.subItems[i];
[self deleteMenuObject:childItem];
[self.treeItemsToRemove addObject:childItem];
}
item.isOpened = @"NO";
}
- (NSMutableArray *)deleteIndexsOfMenuObject:(NSMutableArray *)array{
NSMutableArray * tempArray = @[].mutableCopy;
NSMutableIndexSet * set;
set = [NSMutableIndexSet indexSet];
for (ObjModel * item in array) {
NSIndexPath * path = [NSIndexPath indexPathForRow:[self.dataArray indexOfObject:item] inSection:0];
[tempArray addObject:path];
[set addIndex:path.row];
}
[self.dataArray removeObjectsAtIndexes:set];
return tempArray;
}
这样,就可以实现tableview的树状结构了.