ios 环境下创建树目录

来源:互联网 发布:qemu调试linux内核 编辑:程序博客网 时间:2024/06/05 05:57

需求:

最近在项目中遇到一个需求:自动读取数据库中的纪录,并根据type字段分层,构建目录树。要求能够在点击父节点的时候动态刷新子节点,并完成相关操作。

在windows 环境中,自己也做过或者用过不少目录树的控件,但是ios平台没有自带的tree目录控件,ok,自己动手写一个。

思路:

开始自己想到过简单的用几个array来动态保存每个层级的元素,例如根结点为array1,一级节点就存在array2,三级节点放在array3 ......由此类推,n级节点就放在 arrayn+1中,这样做比较简单,实现起来不复杂,但是有几个致命的缺陷:

1、在层级不能确定的前提下,需要用一个动态数组保存每一级的元素集合,也就是需要二维数组,在每一次点击节点的时候,需要至少做一次查询,并对该二维数组进行修改。实现效率较低。

2、在层级确定的前提下,可以将数组个素确定,但是如果层级发生变化,需要修改,比较麻烦。

最后,自己考虑用树来保存目录结构,并根据点击要素所在的层级,动态更新显示子节点,该方法只需要在程序加载的时候查询一次数据库,大大提高以后的点击操作效率。下图是自己简单思考后画的草图。

实现:

1、定义树形结构,作为数据目录,并将它作为界面操作的数据源

2、定义数据结构,包括节点的子节点,节点名称,以及节点度

3、定义目录在界面上的展现形式,自定义控件。

4、数据库查询操作代码。

核心代码说明:

eTreeMenu.h

@protocol eTreeMenuDelegate<NSObject>

//多选情况,title : 选择名称  sel : 是否选择
-(void)ChooseItemClick:(NSString *)title andSel:(BOOL)sel;
//清除已经选择的叶子节点
-(void)clearChoosedLeaves;
@end

@interface eTreeNode : NSObject
{
    eTreeNode  *parentNode;
    NSArray    *childrenNode;
    NSString   *displayName;
    NSInteger   nodeDepth;
}
@property(nonatomic,assign) NSInteger   nodeDepth;
@property(nonatomic,retain)NSString   *displayName;
@property(nonatomic,retain)NSArray    *childrenNode;
@property(nonatomic,retain)eTreeNode  *parentNode;
@end

@interface eTreeMenu : UIScrollView<eChooseItemViewDelegate>
{

    id<eTreeMenuDelegate>  sdelegate;
    NSMutableDictionary  *dataSource;
    eTreeNode   *rootNode;
    NSInteger   depth;
    float  maxWidth;
    float  maxHeight;
    sqliteCommand  *sqlComd;
    NSMutableArray *showNodes;
    eTreeNode   *Root;
    //选中的node深度
    NSInteger   selectedNodeDepth;
}

@property(nonatomic,retain)id<eTreeMenuDelegate>  sdelegate;
@property(nonatomic,retain)eTreeNode   *Root;
@property(nonatomic,retain)NSMutableArray *showNodes;
@property(nonatomic,retain)sqliteCommand  *sqlComd;
@property(nonatomic,assign) NSInteger   depth;
@property(nonatomic,retain)eTreeNode *rootNode;
@property(nonatomic,retain)NSMutableDictionary  *dataSource;
@end

eTreeMenu.m

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setTreeData];
        //self.backgroundColor=[UIColor lightGrayColor];
        
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame andData:(NSMutableDictionary *)data
{
    self.dataSource=data;
    self = [super initWithFrame:frame];
    if (self) {
        
        self.depth=0;
    }
    return self;
}

//设定数据
-(void)setTreeData
{
    
    [self loadAreaData];
    [self initShowNodeWithRoot];
    [self redrawWithNode:self.Root andSelectNode:nil];
}

//加载数据目录
-(void)loadAreaData
{
    eTreeNode  *root=[self createNodeWithCode:@"900000" andName:@"中国" withDepth:1];
    self.Root=root;
}

//利用递归方法实现各个节点
-(eTreeNode *)createNodeWithCode:(NSString *)code andName:(NSString *)dispName withDepth:(int)curDepth
{
    eTreeNode *node;
    NSString *tableName=@"TAB_AREACODE_NEW";
    NSArray  *cols=[NSArray arrayWithObjects:@"MC",@"CODE",@"PARENT", nil];
    
    //更新树的深度
    self.depth=5;//(self.depth<curDepth)?curDepth:self.depth;
    
    if (self.sqlComd==nil) {
        NSString *dbDir=[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"/DB/"];
        self.sqlComd= [[sqliteCommand alloc] initSqlLiteParam:dbDir andFile:ANALYSIS_DB_NAME];
    }
    
    NSArray *array=[self.sqlComd getValuesFromSqlite:tableName andCols:cols andAdopter:[NSString stringWithFormat:@" TYPE =%d AND PARENT=%@",curDepth+1,code]];
    
    if (array==nil||[array count]<=0) {
        
        //没有子节点是叶子
        node=[[eTreeNode alloc] initWithParent:nil andChildren:nil andName:dispName andDepth:curDepth];
        
    }else
    {
        //还有子节点
        NSMutableArray  *childs=[[NSMutableArray alloc] init];
        for (int i=0; i<[array count]; i++) {
            
            NSString *_title=[[array objectAtIndex:i] objectAtIndex:0];
            NSString *_code=[[array objectAtIndex:i] objectAtIndex:1];
            eTreeNode *childNode=[self createNodeWithCode:_code andName:_title withDepth:curDepth+1];
            [childs addObject:childNode];
        }
        node=[[eTreeNode alloc] initWithParent:nil andChildren:childs andName:dispName andDepth:curDepth];
    }
    return  node;
}

//绘制部分代码
//由根节点,生成树,created by eric 20140115
-(void)initShowNodeWithRoot
{
    //重新申明
    showNodes=[[NSMutableArray alloc] initWithCapacity:self.depth];
    
    if (self.Root!=nil) {
        
        eTreeNode  *node=self.Root;
        
        for (int i=0; i<self.depth; i++) {
            
            [showNodes addObject:node];
            if (node!=nil && node.childrenNode!=nil) {
                
                //子目录不为空,默认选择第一个
                node=[node.childrenNode objectAtIndex:0];
                
            }else
            {
                node=nil;
            }
        }
    }
}

//重新绘制,根据node节点为主,并选择节点 selNode
-(void)redrawWithNode:(eTreeNode *)parentNode andSelectNode:(eTreeNode *)selNode
{
    for (id view in self.subviews) {
        [view removeFromSuperview];
    }
    
    eTreeNode  *tempNode=(selNode==nil)?parentNode:selNode;
    if (showNodes!=nil) {
        //之前的层级保持不变
        for (int i=0; i<tempNode.nodeDepth-1; i++) {
            
            eTreeNode  *nd=[showNodes objectAtIndex:i];
            [self addLeaves:nd andDepth:i andSelect:[showNodes objectAtIndex:i+1]];
        }
        //当前层级发生变化
        for (int i=tempNode.nodeDepth-1; i<self.depth-1; i++) {
            
            [self addLeaves:tempNode andDepth:i andSelect:tempNode];
            [showNodes setObject:tempNode atIndexedSubscript:i];
            
            if (tempNode!=nil && tempNode.childrenNode!=nil) {
                
                //子目录不为空,默认选择第一个
                tempNode=[tempNode.childrenNode objectAtIndex:0];
            }else
            {
                tempNode=nil;
            }
        }
    }
}

//添加叶子节点,node:节点要素  depth:节点深度 ,并选择节点selNode
-(void)addLeaves:(eTreeNode *)node andDepth:(NSInteger )nodeDepth andSelect:(eTreeNode *)selNode
{
    
    NSLog(@"draw the depth:%d",nodeDepth);
    if (nodeDepth>=0) {
        
        if (node.childrenNode!=nil) {
            
            float  butWidth=140.0;
            float  butHeight=32.0;
            float  offsetX=0.0;
            float  offsetY=0.0;
            
            //maxHeight=(maxHeight>nodeDepth * butHeight)?maxHeight:nodeDepth * butHeight;
            //maxWidth=(maxWidth>[node.childrenNode count]*butWidth)?maxWidth:[node.childrenNode count]*butWidth;
            
            for (int i=0; i<[node.childrenNode count]; i++) {
                
                eTreeNode *item=[node.childrenNode objectAtIndex:i];
                eChooseItemView  *nodeItem=[[eChooseItemView alloc] initWithFrame:CGRectMake(offsetX+(butWidth+4)*i, offsetY+(butHeight+5)*nodeDepth, butWidth, butHeight) andTile:item.displayName];
                NSLog(@".....added the item:%@",item.displayName);
                nodeItem.nodeData=item;
                nodeItem.parentNode=node;
                [self addSubview:nodeItem];
                
                if (item.nodeDepth==selNode.nodeDepth&&[item.displayName isEqualToString:selNode.displayName]) {
                    
                    [nodeItem changeMode];
                }
                
                nodeItem.delegate=self;
            }
            //设定视图大小
            self.contentSize=CGSizeMake(([node.childrenNode count]+1)*butWidth, nodeDepth * butHeight);
        }
    }
}


//添加叶子节点,node:节点要素  depth:节点深度
-(void)addLeaves:(eTreeNode *)node andDepth:(NSInteger )nodeDepth
{
    if (nodeDepth>=0) {
        
        if (node.childrenNode!=nil) {
            
            float  butWidth=140.0;
            float  butHeight=32.0;
            float  offsetX=0.0;
            float  offsetY=0.0;
            
            //maxHeight=(maxHeight>nodeDepth * butHeight)?maxHeight:nodeDepth * butHeight;
            //maxWidth=(maxWidth>[node.childrenNode count]*butWidth)?maxWidth:[node.childrenNode count]*butWidth;
            
            for (int i=0; i<[node.childrenNode count]; i++) {
            
                eTreeNode *item=[node.childrenNode objectAtIndex:i];
                eChooseItemView  *nodeItem=[[eChooseItemView alloc] initWithFrame:CGRectMake(offsetX+(butWidth+4)*i, offsetY+(butHeight+5)*nodeDepth, butWidth, butHeight) andTile:item.displayName];
                NSLog(@".....added the item:%@",item.displayName);
                nodeItem.nodeData=item;
                nodeItem.parentNode=node;
                [self addSubview:nodeItem];
                nodeItem.delegate=self;
            }
            //设定视图大小
            self.contentSize=CGSizeMake(([node.childrenNode count]+1)*butWidth, nodeDepth * butHeight);
        }
    }
}

-(void)ChooseItemClick:(UIButton *)sender andSel:(BOOL)sel andTitle:(NSString *)title
{
    eChooseItemView  *send=(eChooseItemView *)sender;
    
    if (send.nodeData.nodeDepth != self.depth )
    {
        [self redrawWithNode:send.parentNode andSelectNode:send.nodeData];
        [self redrawWithNode:send.parentNode andSelectNode:send.nodeData];
    }
    //如果选中节点是之前节点的子节点,清除之前选中项目
    if (selectedNodeDepth<send.nodeData.nodeDepth) {
        
        [self.sdelegate clearChoosedLeaves];
    }
    selectedNodeDepth=send.nodeData.nodeDepth;
    [self.sdelegate ChooseItemClick:title andSel:sel];
}
-(void)dealloc
{
    [dataSource release];
    [rootNode release];
    [sqlComd release];
    [showNodes release];
    [Root release];
    [super dealloc];

}
@end


展示效果:

补充:

1、相关代码已经上传到csdn,欢迎各位下载。下载地址: http://download.csdn.net/detail/xwz19861215311x/6858163

2、由于时间关系,代码没有做优化,存在一些bug,欢迎各位批评指正。(QQ:435011569)

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 天正打图窗户线条太粗怎么办 孩子在幼儿园不敢跟老师说话怎么办 温州教育准考证号密码忘了怎么办 高等继续教育网打不开课程怎么办 安运继续教育的登录密码忘了怎么办 金蝶k3账套管理打不开了怎么办 仁和会计课堂app不能用怎么办 光大银行已经下卡了终审被拒怎么办 过了上诉期和申诉期该怎么办 北外大四学生要实习半年课程怎么办 电脑发给手机的文件过期了怎么办 农民给土地卖了30年后怎么办 家长发家长群作业太多老师怎么办 在考试中心补不了四级成绩怎么办 微信登录密码不记得了怎么办 欠农民工工资不给怎么办老板说没钱 国外期刊催问稿件不理睬怎么办 老公离不开老婆也离不开小三怎么办 出轨被老婆发现还和小三联系怎么办 老公出轨后回家老婆不想原谅怎么办 小三和原配打架都住院了怎么办 毕业太多年查不到学历认证怎么办 没有做税种核定开了票怎么办 在学信网上查不到学历信息怎么办 学信网手机号换了密码忘了怎么办 学信网手机号换了密码也忘了怎么办 学信网上学习形式是星号怎么办 新手机号已被注册微店买家怎么办 微信号被冻结了里面的钱怎么办 不懂公司产品却要接待老外怎么办 上菜时发现桌面摆不下新菜怎么办 超市买到过期产品商家不赔尝怎么办 皇帝成长计划2俘虏的士兵怎么办 晚上楼上有挪桌子的声音怎么办 金灶茶具出故障码e7怎么办 起亚k2灯泡掉进大灯总成怎么办 衣服上拆过线的针孔怎么办 驾考科目二坡道定点熄火怎么办 穿着超短裤感觉要漏屁股怎么办 台式电脑开机后无法进入系统怎么办 产后两年了肚子肥胖松弛怎么办