导航栏协议方法UINavigationControllerDelegate

关于UINavigationControllerDelegate:

  • Delegate中一共有6个方法。其中两个跟控制器ViewController的跳转有关、有两个跟屏幕的旋转有关、有两个跟导航栏动画有关(可以设计交互式或者非交互式的转场动画)。

 前提配置:为了下面所说的测试都能如期的进行,有几个步骤是需要设置好的

1、声明UINavigationControllerDelegate协议

@interface ViewControllerOne () <UINavigationControllerDelegate>

2、遵守该协议

self.navigationController.delegate = self;

3、在遵守该协议的控制器中写出需要用到的协议方法


 

一、首先介绍下跟控制器的跳转相关的两个协议方法:

// Called when the navigation controller shows a new top view controller via a push, pop or setting of the view controller stack.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    NSLog(@"~~~~~~~~~~willShowViewController");
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    NSLog(@"~~~~~~~~~~didShowViewController");
}

说明:

1、当控制器push、pop、直接设置navigationController的controllers属性,都是可以触发这两个方法的。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    ViewControllerTwo *vcTwo = [[ViewControllerTwo alloc] init];
    
    // 可触发
    [self.navigationController pushViewController:vcTwo animated:YES];
    
    /* 不可触发
    [self.view addSubview:vcTwo.view];
    [self addChildViewController:vcTwo];
    [vcTwo didMoveToParentViewController:self];
    */
    
    /* 不可触发
    [self presentViewController:vcTwo animated:YES completion:nil];
    */
    
    /* 可触发
    self.navigationController.viewControllers = @[self, vcTwo];
    */
}

 

2、为了能够准确的理解这两个方法,一定要记住这个是navigationController的协议方法。对它来说,即将进入这个控制器栈时调用willShow方法,已经进栈后调用didShow方法。

当vc1-push-vc2时,是vc2willShow、vc2didShow,

当vc2-pop-vc1时,是vc1willShow、vc1didShow。

 

3、因为navigationController自身、凡是进栈后的控制器都能够拿到navigationController这个对象,因此都可以成为它的代理。但是,有两个原则:

(1)始终以最新成为代理的为准。

(2)当最新成为代理的控制器销毁后(因为代理是weak,所以不会强留代理),第二新的代理成为接班者。

但是有个注意点:一个控制器销毁是在另一个控制器didShow之后,一个控制器成为接班者是在didShow之后。

举例如下:vc1、vc2都是navigationController的代理。过程是vc1-push-vc2,然后vc2-pop-vc1。

vc1-push-vc2的过程是:vc1是真代理、vc2willShow、vc2didshow、vc2成为真代理。

vc2-pop-vc1的过程是:vc2是真代理、vc1willShow、vc1didShow、vc1成为真代理。


 

二、然后介绍下跟屏幕的旋转有关的代理(真的不常用,而且真的比较坑)

首先要说明白的是,屏幕旋转有三个相关的地方:手机上的旋转开关、项目在Xcode上的配置、接下来要介绍的这2个协议方法。

// 返回-导航控制器支持的设备方向
// 每次旋转设备的时候询问(前提是iPhone上的屏幕旋转开关是开着的)
- (UIInterfaceOrientationMask)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    NSLog(@"~~~~~设置方法设置导航控制器支持的设备方向~~~~~");
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

// 这个方法设置导航控制器的首选设备方向
- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController {
    NSLog(@"~~~~~这个方法设置导航控制器的首选设备方向~~~~~");
    return UIInterfaceOrientationLandscapeLeft;
}

现在表述下手机上的旋转开关、Xcode上的配置、协议方法、屏幕的方向四者之间的联系:

(1)当手机上的旋转开关关闭时,Xcode上的配置失效、当设备旋转时协议方法不调用、屏幕只能是竖屏显示。

(2)当手机上的旋转开关开着时,屏幕的可旋转方向由「Xcode上的配置」和「可旋转方向的协议方法」两者的交集决定。当设备旋转时,「可旋转方向的协议方法」被调用,屏幕会旋转成交集中存在的方向。

(3)至于屏幕最初显示的方向的依据现象是这样的:只要「Xcode上的配置」,包含Portrait方向(即竖屏),则最初显示的方向都是竖屏。只要「Xcode上的配置」不包含Portrait(即竖屏),则最初显示的方向就是设备往左(即屏幕往右)的方向(可以通过下面图像进行理解)。至于「首选设备方向的协议方法」一直不调用。在这种情况下,无关手机上的旋转开关的状态(不管开关,前面文字描述的内容依然成立)。

 吐槽:

(1)虽然Xcode上的配置写的是“Device Orientation”,但是真实功能却是“可选方向”的作用。并且真实的可选方向,还必须是「Xcode上的配置」和「可旋转方向协议方法」两者的交集。

(2)「首选设备方向的协议方法」一直不被调用。


三、简介下跟导航栏转场动画相关的两个协议方法

// 没有交互的转场动画
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                  animationControllerForOperation:(UINavigationControllerOperation)operation
                                               fromViewController:(UIViewController *)fromVC
                                                 toViewController:(UIViewController *)toVC {
    NSLog(@"~~~~~~~~~~%ld~%@~%@", operation, fromVC.class, toVC.class);
    return nil;
}

// 有交互的转场动画
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                         interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
    NSLog(@"~~~~~~~~~~%@", animationController);
    return nil;
}

免责说明:

关于转场动画,不在该篇文章的讨论范围。其实也是因为内容比较多,后面在专门重起一文再议。

简单闲扯下:

1、转场动画可以分为交互式与非交互式,如果设置非交互式的用上面第一个协议方法就可以了。

2、第一个协议方法中的operation参数,可以知道当前进行的是push还是pop操作。

 

posted @ 2018-05-28 21:39  码出境界  阅读(1982)  评论(0编辑  收藏  举报