說明:寫的東西是參照某位大神寫的博客,但是我自己的數據他有些沒有,然後我就根據大神的博客重新寫了下,希望對大家有用
1.數據的形式,請求下來的數據將會是如下格式
@property (nonatomic, strong) NSString *itemParentId;//父節點的id @property (nonatomic, strong) NSString *itemId;//本節點的id @property (nonatomic, strong) NSString *itemName;//本節點的名稱 @property (nonatomic, assign) BOOL expand;//該節點是否處於展開狀態這些數據中有父節點的ID和自身的ID,還有自身的名字,並且自己寫一個屬性expand,之後來判斷該節點是否處於展開或者收起狀態
2.那麼根據這個節點我們創建一個Model,代碼如下,代碼中我寫好了注釋
創建一個Node類繼承於NSObject
Node.h中的代碼:
#import@interface Node : NSObject //這裡是數據 @property (nonatomic, strong) NSString *itemParentId;//父節點的id @property (nonatomic, strong) NSString *itemId;//本節點的id @property (nonatomic, strong) NSString *itemName;//本節點的名稱 @property (nonatomic, strong) NSString *itemIndex;//本節點在該級菜單中的索引值(這個值可以不用關注,這是我自己用到的數據) @property (nonatomic, assign) BOOL expand;//該節點是否處於展開狀態 @property (nonatomic, strong) NSString *siteSSCID;//(這個值也不用關注,也是我自己的數據的東西) /** * 快速實例化該對象模型 * * @param itemParentId 父節點的id * @param itemId 本節點的id * @param itemName 本節點的名稱 * @param itemIndex 本節點在該級菜單中的索引值 * @param expand 該節點是否處於展開狀態 * * @return 一個node實例 */ - (instancetype)initWithParentId:(NSString *)itemParentId nodeId:(NSString *)itemId name:(NSString *)itemName index:(NSString *)itemIndex siteSSCID:(NSString *)itemSiteSSCID expand:(BOOL)expand; @end
Node.m中的代碼
#import "Node.h" @implementation Node - (instancetype)initWithParentId:(NSString *)itemParentId nodeId:(NSString *)itemId name:(NSString *)itemName index:(NSString *)itemIndex siteSSCID:(NSString *)itemSiteSSCID expand:(BOOL)expand{ self = [self init]; if (self) { self.itemParentId = itemParentId; self.itemId = itemId; self.itemName = itemName; self.itemIndex = itemIndex; self.siteSSCID = itemSiteSSCID; self.expand = expand; } return self; } @end
3.創建一個TreeTableView類繼承於UITableView,其中的注釋在代碼中,我就直接粘貼代碼了
TreeTableView.h中的代碼
#import@interface TreeTableView : UITableView @property (nonatomic , strong) NSArray *dataS;//傳遞過來已經組織好的數據(全量數據) @property (nonatomic , strong) NSMutableArray *tempData;//用於存儲數據源(部分數據,這個數據是根據dataS來最初顯示在界面上的菜單的名字) @property (nonatomic , strong) void (^selectBlock)(NSString *);//這個block是我用來傳當點擊到最後子節點的時候,具體的傳值我還沒寫
-(NSMutableArray *)createTempData : (NSArray *)data;//初始化表格數據(這個方法是根據總數據先初始化最開顯示的最上層的菜單,然後得到tempData) @end
TreeTableView.m中的代碼
#import "TreeTableView.h" #import "Node.h" @interface TreeTableView (){ NSMutableDictionary *_dic;//處理重復數據用 NSInteger _depth;//深度,就是是第幾級菜單 } @end @implementation TreeTableView -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame style:UITableViewStyleGrouped]; if (self) { _dic = [@{} mutableCopy]; self.dataSource = self; self.delegate = self; } return self; } /** * 初始化數據源 */ -(NSMutableArray *)createTempData : (NSArray *)data{ NSMutableArray *tempArray = [@[] mutableCopy]; NSMutableArray *keys = [@[] mutableCopy]; for (int i=0; i //首先展示的數據是tempData的數據return self.tempData.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *NODE_CELL_ID = @"node_cell_id"; //定義cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NODE_CELL_ID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NODE_CELL_ID]; }Node *node = [self.tempData objectAtIndex:indexPath.row];//取到數據中node的name _depth = 0;//全局變量,深度置為0 NSInteger tem = [self findDepthOfNode:node];//找到某個node在整個樹形菜單的深度//處理界面展示的層次關系,在前面加空格實現,也可以自定義cell,在前面加上imageView來更形象的展示,我就沒有具體寫了 NSMutableString *name = [NSMutableString string]; for (int i=0; i cell.textLabel.font = [UIFont systemFontOfSize:15.0];//設置cell中字體的大小 cell.textLabel.text = name;//設置cell顯示的內容 cell.backgroundColor = [UIColor brownColor];//設置cell的背景顏色 return cell; } //這個方法是用來找它的深度的。根據某個節點找到節點在整個菜單中深度(作用就是會在後面收起的時候做判斷) - (NSInteger)findDepthOfNode:(Node *)node{ Node * nextNode;//根據傳過來的node判斷是不是是根節點(我設置的根節點,就是沒有父節點的節點的父節點ID為“0”) if (![node.itemParentId isEqualToString:@"0"]) {//如果不是父節點,那麼它的深度加一 _depth ++;//然後去循環找視圖展示的數據中,這個節點的父節點 for (int i = 0; i < self.tempData.count; i++) { nextNode = [self.tempData objectAtIndex:i];//判斷如果找到有這樣一個父節點數據在tempData中那麼就break if ([node.itemParentId isEqualToString:nextNode.itemId]) { break; } }//用遞歸的思想循環找 [self findDepthOfNode:nextNode]; }//最終獲取到數據在tempData中的深度(也就是在第幾層) return _depth; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ return 0.01; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 40; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 0.01; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ //這裡是關鍵,就是點擊展開或者收起的代碼 BOOL expand = NO; NSUInteger startPosition = indexPath.row+1;//點擊某一行,獲取開始的位置 NSUInteger endPosition = startPosition;//結束的位置 Node *parentNode = [_tempData objectAtIndex:indexPath.row];//獲取到某一行的節點//這裡可以先不用管,我還沒有寫具體的內容,這裡是判斷如果點擊之後再無子節點,那麼它的層級最低,可以將點擊的東西傳值到其他頁面 if (self.selectBlock) { self.selectBlock(parentNode.itemName); }//在總的數據dataS中查找for (int i=0; i //判斷語句前一個語句是查找所有數據,一個個查看它的父節點是不是點擊的那個,是的話就插入數據到表格的相應位置,否則刪除表格中相應的數據 if ([node.itemParentId isEqualToString:parentNode.itemId] && ![node2.itemId isEqualToString:node.itemId]) {node.expand = !node.expand; if (node.expand) { [_tempData insertObject:node atIndex:endPosition]; expand = YES; }else{ expand = NO; endPosition = [self removeAllNodesAtParentNode:parentNode]; break; } endPosition++; } } //獲得需要修正的indexPath NSMutableArray *indexPathArray = [NSMutableArray array]; for (NSUInteger i=startPosition; i NSUInteger startPosition = [_tempData indexOfObject:parentNode]; NSUInteger endPosition = startPosition + 1; _depth =0; NSInteger y = [self findDepthOfNode:parentNode]; for (NSUInteger i=startPosition+1; istartPosition) { [self.tempData removeObjectsInRange:NSMakeRange(startPosition+1, endPosition-startPosition-1)]; } return endPosition; } @end
4.這兩個類創建完成,在ViewController中的初始化並調用
ViewController.h代碼
#importViewController.m代碼@interface ViewController : UIViewController @end
#import "ViewController.h" #import "TreeTableView.h" #import "Node.h" @interface ViewController () @property (nonatomic,strong)TreeTableView *treeTableView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //初始化數據 self.treeTableView.dataS = [self LoadDataForTableView]; self.treeTableView.tempData = [self.treeTableView createTempData:self.treeTableView.dataS]; //加載視圖 [self.view addSubview:self.treeTableView]; } #pragma mark *** Private Mathod *** - (NSArray *)LoadDataForTableView{ // 構造數據 // 構造總的數據 //我這裡是以“0”作為最根節點,如果是其他作為根節點,要在代碼中做相應的修改 Node *node = [[Node alloc]initWithParentId:@"0" nodeId:@"國家1" name:@"中國" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node1 = [[Node alloc]initWithParentId:@"0" nodeId:@"國家2" name:@"俄羅斯" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; //這裡的ParentId一定是父節點的nodeId Node *node2 = [[Node alloc]initWithParentId:@"國家1" nodeId:@"省份1" name:@"四川" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node3 = [[Node alloc]initWithParentId:@"國家1" nodeId:@"省份2" name:@"浙江" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node4 = [[Node alloc]initWithParentId:@"國家1" nodeId:@"省份3" name:@"江蘇" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node5 = [[Node alloc]initWithParentId:@"省份1" nodeId:@"省份1城市1" name:@"成都" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node6 = [[Node alloc]initWithParentId:@"省份1" nodeId:@"省份1城市2" name:@"巴中" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node7 = [[Node alloc]initWithParentId:@"省份1" nodeId:@"省份1城市3" name:@"內江" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node8 = [[Node alloc]initWithParentId:@"省份2" nodeId:@"省份2城市1" name:@"溫州" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node9 = [[Node alloc]initWithParentId:@"省份3" nodeId:@"省份3城市1" name:@"常州" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node10 = [[Node alloc]initWithParentId:@"國家2" nodeId:@"國家2省份1" name:@"莫斯科" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node11 = [[Node alloc]initWithParentId:@"國家2" nodeId:@"國家2省份2" name:@"除了莫斯科,我也不知道有那個城市" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; //造個四級菜單數據 Node *node12 = [[Node alloc]initWithParentId:@"省份1城市1" nodeId:@"省份1城市1區域1" name:@"青羊區" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node13 = [[Node alloc]initWithParentId:@"省份1城市1" nodeId:@"省份1城市1區域2" name:@"高新區" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; Node *node14 = [[Node alloc]initWithParentId:@"省份1城市1" nodeId:@"省份1城市1區域3" name:@"武侯區" index:@"這個數據是我自己的數據你要不要無所謂" siteSSCID:@"這個數據也是" expand:NO]; NSArray *arry = @[node,node1,node2,node3,node4,node5,node6,node7,node8,node9,node10,node11,node12,node13,node14]; return arry; } #pragma mark *** Lazy Loading *** - (TreeTableView *)treeTableView{ if (!_treeTableView) { _treeTableView = [[TreeTableView alloc]initWithFrame:CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height)]; } return _treeTableView; }