主界面里面有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> 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
,它没法返回到主界面。
写到这儿,我发现我就像医生一样做了一台手术,终于把主动脉和分支血管打通了。
上面没有涉及内存释放问题,处理方法可以参看代码,如果在代码中发现问题,希望留言指出。
http://git.oschina.net/juwenz/NestedNavigationController