# NestedNavigationController **Repository Path**: juwenz/NestedNavigationController ## Basic Information - **Project Name**: NestedNavigationController - **Description**: 解决嵌套navigationController问题 - **Primary Language**: Objective-C - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2013-11-30 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ##问题描述 ###系统模块图 ![系统模块图][1] ###想要实现的效果 主界面里面有2个模块,点击其中任意模块后进入子模块,在每个子模块里面有4个tab(如上图), 每个tab分别由一个导航条(navigationcontroller)控制(一共四个),我想既能从主界面进入子模块,也能从子模块返回主界面。 ##尝试的方法 ###看官小心,希望看后不要该解题思路禁锢,建议先思考,再看 1.主界面点击子模块时,新建一个`UIWindow`视图, 然后把该子模块的四个navigationcontroller初始化好以后,分别加入到`UITabBarController`中,并且作为`UIWindow 的 rootViewController`,最后把`UIWindow`的实例添加到当前页面中。结果是能够进去子模块,但是无法返回到主界面; 2.点击子模块后,不创建`UIWindow`,直接创建`UITabBarController`,然后直接添加到当前页面中。结果是切换tab时报错; 3.主界面点击子模块进入一个`UIViewController`,按照方案1新建一个`UIWindow` , 最后 把window添加到当前页面中。结果也是无法返回主界面。 ##最终方法 经过不断尝试,发现第三种方案可以实现想要的效果,具体步骤如下: 1.在TopViewController点击模块事件中,做如下处理 -(IBAction)gotoModule1:(id)sender{ Module1ViewController *module1VC = [[Module1ViewController alloc] init]; [self.navigationController pushViewController:module1VC animated:YES]; } 2.在Module1ViewController.m中合适的事件(我选择-viewDidLoad:)中,加入初始化UIWindow和tab的代码,如下 - (void)viewDidLoad { [super viewDidLoad]; CGRect bounds = self.view.bounds; //初始化tab1要显示的viewController Tab1ContentViewController *tab1ContentVC = [[Tab1ContentViewController alloc]init]; //这句代码是建立主界面和子模块返回的桥梁 //..........此处代码待补充..........① Tab2ContentViewController *tab2ContentVC = [[Tab2ContentViewController alloc]init]; UINavigationController *navi1 = [[UINavigationController alloc]initWithRootViewController:tab1ContentVC]; UINavigationController *navi2 = [[UINavigationController alloc]initWithRootViewController:tab2ContentVC]; UITabBarController *tab = [[UITabBarController alloc]initWithNibName:@"UITabBarController" bundle:nil]; //把navi1和navi2加入到tab中 tab.viewControllers = @[navi1,navi2]; //这段代码是为了适配屏幕,具体什么情况去掉代码运行,注意ios56和ios7运行效果不同,需要做版本适配才可正常显示 window = [[UIWindow alloc] initWithFrame:CGRectMake(bounds.origin.x, bounds.origin.y-20, bounds.size.width, bounds.size.height+20)]; window.hidden = NO; window.userInteractionEnabled=YES; //切割超出window的部分 window.clipsToBounds = YES; //设置UIWindow的rootController window.rootViewController=tab; [self.view addSubview:window]; window = nil; } 3.运行上面代码,能够实现从主界面进入子模块,但是怎么返回呢?接下来的工作就是为了解决这个问题。 首先新建一个protocol,命名为BackProtocol.h,内容如下 -(void)back:(id)sender; 接着,让子模块Module1VC实现BackProtocol协议,在back方法中加入代码 -(void)back:(id)sender{ [self.navigationController popViewControllerAnimated:YES]; } 这里先说明一下,在程序中使用导航条返回到上一个界面的方法总是调用`[self.navigationController popViewControllerAnimated:YES];`,本程序也不例外,只是导航条个数不是一个,而是**嵌套**的**多个**,所以一定要理解清楚`self.navigationController`对象是谁; 4.下面,在`Tab1ContentViewController.h`中加入一个property `@property (nonatomic,copy) id backDelegate;` 然后在`Tab1ContentViewController `的导航条左边加一个button,事件类型是`UIButtonTouchUpInside `, 方法名字`back:`,方法内容 if ([_backDelegate respondsToSelector:@selector(back:)]) { [_backDelegate back:sender]; } 写到这,你可能已经明白我想干嘛了,把点击事件交给delegate,让`Module1ViewController`处理。 5.最后在上面①出加上 `tab1ContentVC.backDelegate = self;` 即可; 好了 ,分析一下为什么需要让`Module1ViewController`处理,因为`Module1ViewController`的`self.navigationController`是从主界面来的,是主界面的导航条;而`tab1ContentVC`的`self.navigationController`是`navi1`,它没法返回到主界面。 写到这儿,我发现我就像医生一样做了一台手术,终于把主动脉和分支血管打通了。 ##说明 上面没有涉及内存释放问题,处理方法可以参看代码,如果在代码中发现问题,希望留言指出。 ##附上代码 [1]: http://static.oschina.net/uploads/space/2013/1130/144502_8zVK_1000730.jpg