iOS开发:UINavigationController

一、UINavigationController介绍

1、导航控制器继承自UIViewController,本身是一个控制器。

2、导航控制器是一个容器,可以容纳视图控制器,通过入栈和出栈来管理容器内的控制器。在纵向管理视图控制器上是非常重要的。

3、导航控制器内封装了navigationBar,一个导航控制器都有一个导航条。

示例代码:

1、导航控制器相关属性

-(void)showViewController{
    //数组:导航栈内所有的视图控制器都在这个数组内
    NSArray * viewControllers = self.navigationController.viewControllers;
    NSLog(@"viewControllers = %@",viewControllers);
    //导航栈内控制器的个数
    NSUInteger numViewController = viewControllers.count;
    NSLog(@"numViewController = %ld",numViewController);
    //当前显示出来的视图控制器
    UIViewController * visibleController = [self.navigationController visibleViewController];
    NSLog(@"visibleController = %@",visibleController);
    //栈顶的视图控制器
    UIViewController * topController = [self.navigationController topViewController];
    NSLog(@"topController = %@",topController);
}

日志输出如下:


2、导航控制器入栈方法

-(void)goToNext:(UIButton *)btn{
    SecondViewController * secondVC = [[SecondViewController alloc] init];
#if 0
    //设置navigationcontroller所有的控制器
    self.navigationController.viewControllers = @[self,secondVC];
#elif 0
    //设置navigationcontroller所有的控制器
    NSArray * viewControllers = @[self,secondVC];
    [self.navigationController setViewControllers:viewControllers animated:YES];
#elif 1
    [self.navigationController pushViewController:secondVC animated:YES];//常用方法
#endif
    //导航栈内的控制器个数
    NSLog(@"num = %lu",self.navigationController.viewControllers.count);
}

3、导航控制器出栈方法

-(void)goToBack:(UIButton *)btn{
#if 1
    //将当前视图控制器弹出栈
    [self.navigationController popViewControllerAnimated:YES];
#elif 0
    //某个视图控制器之上的控制器都弹出栈
    [self.navigationController popToViewController:self.navigationController.viewControllers[0] animated:YES];
#elif 0
    //将根视图控制器之上的所有控制器都弹出栈
    [self.navigationController popToRootViewControllerAnimated:YES];
#endif
    NSLog(@"num = %lu",self.navigationController.viewControllers.count);
}

二、代理方法: < UINavigationControllerDelegate >

//设置代理
self.navigationController.delegate = self;
//将要显示控制器
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    //PS:
    //所有在导航栈内的控制器只要将要显示都会来到这个方法,比如这个方法写在firstViewController这个类内,self.navigationController.delegate = self;当secondViewController推入第三个thirdViewController时也会来到这个方法。
//原因:导航栈在推入一个新的控制器的时候,上个控制器并未销毁,其代理还是存在的。所以会调用代理方法。
}
//控制器显示已经完成
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    NSLog(@"viewcontroller = %@",viewController);



}


三、自定义控制器

说明:

1、导航控制器在推入下一个控制器的时候,导航条左侧有个系统默认的返回按钮,单击此返回按钮会返回到上一页。

2、同时长按屏幕向左滑动也会回到上一页。

3、如果系统的返回按钮被自定义的按钮覆盖的话,长按屏幕向左滑动的功能就会失效。自定义导航控制器需要注意这个问题。

比如用下面的方法自定义导航条的左侧按钮:

-(void)setLeftBarItem{
    UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.frame = CGRectMake(0, 0, 80, 40);
    [btn setTitle:@"返回" forState:UIControlStateNormal];
    UIBarButtonItem * leftItem = [[UIBarButtonItem alloc] initWithCustomView:btn];
    [btn addTarget:self action:@selector(goToBack:) forControlEvents:UIControlEventTouchUpInside];
    self.navigationItem.leftBarButtonItem = leftItem;
}


.h文件

#import <UIKit/UIKit.h>
//继承自UINavigationController
@interface LKLNavigationController : UINavigationController
@end

.m文件

#import "LKLNavigationController.h"

@interface LKLNavigationController ()<UINavigationControllerDelegate>
@property (nonatomic,weak)id popDelegate;
@end

@implementation LKLNavigationController

+(void)initialize{
    //在此方法内进行一些默认属性的设置
}

-(instancetype)init{
    self = [super init];
    if (self) {
       //导航条的初始化方法:- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;
        //貌似不会调用这个方法,所以一些默认的属性设置写在此方法内是不会执行的。
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //实现滑动功能
    [self slideToPre];
   
}


//重写父类的push..方法
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    //这个数组里放置了所有被push到导航栈里的控制器,并且第一个在最底层,最后一个在最顶层
    //需要说明的是:
    //在调用父类方法之前,判断导航栈内的控制器个数
    //此时在此方法内打印出的是0,如下代码。
    NSArray * controllers1 = self.viewControllers;
    NSLog(@"LKLNavigatinController.ViewControllers.count = %lu",controllers1.count);// 0
    
    
    if (self.viewControllers.count == 0) {
        //此时证明下面将要push的是根控制器
    }
    else{
        //下面推入的不是根控制器时,自定义导航条左右两边的按钮
        //存在的问题:覆盖系统的导航条返回按钮滑动功能失效
        //左边
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(backToPre)];
        
        //右边
        viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(backToRoot)];
        
        viewController.hidesBottomBarWhenPushed = YES;
    }
    
    
    //新控制器入栈
    [super pushViewController:viewController animated:animated];
    
    
    //在调用父类方法之后,判断导航栈内的控制器个数
    //此时在此方法内打印出的是1,如下代码。
     NSArray * controllers2 = self.viewControllers;
    NSLog(@"RRRLKLNavigatinController.ViewControllers.count = %lu",controllers2.count);
    if (self.viewControllers.count == 1) {
        //此时证明上面刚push进来的是根控制器
    }
}

#pragma mark - 点击导航按钮时调用的方法
-(void)backToPre{
    [self popViewControllerAnimated:YES];
}

-(void)backToRoot{
    [self popToRootViewControllerAnimated:YES];
}

#pragma mark - 实现滑动返回功能
-(void)slideToPre{

#if 0
    //清空滑动返回手势的代理,就能实现滑动返回,
    //首页没有自定义导航条的左右按钮,所以不应该清除。所以清除代理应区分情况,下面的代码放在这里就不合适
    self.interactivePopGestureRecognizer.delegate = nil;
#else
    //既然不能在此清除,那么久先记录下手势代理
    //在导航控制器的代理方法中选择时机清除代理,
    _popDelegate = self.interactivePopGestureRecognizer.delegate;
    
    //遵守<UINavigationControllerDelegate>让自己成为自己的代理
    self.delegate = self;
#endif
    
}

#pragma mark - <UINavigationControllerDelegate>

#pragma mark - 导航控制器的代理方法
//只要控制器发生改变就会调用这两个方法
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    
}

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    
    if (viewController == self.viewControllers[0]) {
        //根控制器没有覆盖系统的导航条按钮  最好不要修改系统的代理 否则可能产生问题
        self.interactivePopGestureRecognizer.delegate = _popDelegate;
    }
    else{
        self.interactivePopGestureRecognizer.delegate = nil;
    }
}

@end



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值