你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS 樹形結構菜單

iOS 樹形結構菜單

編輯:IOS開發綜合

說明:寫的東西是參照某位大神寫的博客,但是我自己的數據他有些沒有,然後我就根據大神的博客重新寫了下,希望對大家有用

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

這樣做完之後,我們就把數據的Model構建完成了,現在根據這個Model來創建樹型菜單

 

 

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代碼

 

#import 

@interface ViewController : UIViewController


@end
ViewController.m代碼

 

 

#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;
}

 

\

 

 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved