嵌套 NavigationController 问题讨论与解决方法

问题描述

系统模块图

嵌套 NavigationController 问题讨论与解决方法_第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> backDelegate;
然后在Tab1ContentViewController的导航条左边加一个button,事件类型是UIButtonTouchUpInside, 方法名字back:,方法内容

    if ([_backDelegate respondsToSelector:@selector(back:)]) {
        [_backDelegate back:sender];
    }

写到这,你可能已经明白我想干嘛了,把点击事件交给delegate,让Module1ViewController处理。
5.最后在上面①出加上 tab1ContentVC.backDelegate = self; 即可;

好了 ,分析一下为什么需要让Module1ViewController处理,因为Module1ViewControllerself.navigationController是从主界面来的,是主界面的导航条;而tab1ContentVCself.navigationControllernavi1,它没法返回到主界面。

写到这儿,我发现我就像医生一样做了一台手术,终于把主动脉和分支血管打通了。

说明

上面没有涉及内存释放问题,处理方法可以参看代码,如果在代码中发现问题,希望留言指出。

附上代码

http://git.oschina.net/juwenz/NestedNavigationController

你可能感兴趣的:(ios)