UINavigationController 层级关系及一些常用设置

UINavigationController一直是iOS开发中最常用的控件之一,但是一般就是工程开始时对其做一些统一的处理。后期操作就比较少了。导致虽然其很常用但是我们的熟悉程度却不是很高。今天就来记录一下我们常用的这个控件.

UINavigationController继承自UIViewController,是一个基于栈的容器型控制器。既然是容器,他就能装一些东西。比如UIView能添加一些子视图,UINavigationController装的就是视图控制器。

一个UINavigationController包含了几个部分:

1.Navigation Stack 导航栈,它以栈的形式来管理视图控制器。栈的一个视图控制器(栈底),称为根视图控制器,其他称为子视图控制器。栈中的控制器可以通过self.navigationController找到UINavigationController的实例。

2.UINavigationBar导航条 栈中的视图控制器会在顶部加一个导航条,虽然NavigationBar显示在子视图控制器的界面上,但是它是由UINavigationController实例管理的,不过导航条的内容却是由子视图控制器来决定的(通过self.navigationItem设置)

3.UIToolbar工具栏,UINavigationController在子视图的底部提供了工具栏,默认不显示,也很少用到。

常用的属性

// 栈顶VC
@property(nullable, nonatomic,readonly,strong) UIViewController *topViewController;
// 如果存在模态视图控制器则返回模态视图控制器,否则顶视图控制器。
@property(nullable, nonatomic,readonly,strong) UIViewController *visibleViewController;
// 导航控制器目前栈中所管理的VC 
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;
// 导航栏是否隐藏
@property(nonatomic,getter=isNavigationBarHidden) BOOL navigationBarHidden;
// 导航栏
@property(nonatomic,readonly) UINavigationBar *navigationBar;
// 工具栏是否隐藏, 默认为YES
@property(nonatomic,getter=isToolbarHidden) BOOL toolbarHidden
// 工具栏
@property(null_resettable,nonatomic,readonly) UIToolbar *toolbar

手势相关的属性

// 返回手势识别器
@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer
// 属性为YES时,当键盘出现时,导航控制器的navigationBar工具栏将被隐藏。当键盘关闭时,这些条将保持隐藏状态,但只要在内容区域轻击一下,就会显示它们。
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenKeyboardAppears
// 当用户滑动时,导航控制器的导航栏和工具栏将被隐藏(向上滑动)或显示(向下滑动)。工具栏只有在有项目时才参与。
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnSwipe 
// 手势识别器,如果滑动条将隐藏或显示,它将触发该手势识别器。不要更改委托或试图通过覆盖此方法来替换此手势。
@property (nonatomic, readonly, strong) UIPanGestureRecognizer *barHideOnSwipeGestureRecognizer NS_AVAILABLE_IOS(8_0)
// 当UINavigationController的垂直大小类是紧凑的时,隐藏UINavigationBar和UIToolbar。
@property (nonatomic, readwrite, assign) BOOL hidesBarsWhenVerticallyCompact
// 当用户点击时,导航控制器的navigationBar & toolbar将被隐藏或显示,这取决于导航栏的隐藏状态。工具栏只有在有要显示的项目时才会显示。
@property (nonatomic, readwrite, assign) BOOL hidesBarsOnTap
// 手势识别器,用于识别由于内容的点击而隐藏或显示的bar。不要更改委托或试图通过覆盖此方法来替换此手势。
@property (nonatomic, readonly, assign) UITapGestureRecognizer *barHideOnTapGestureRecognizer

常用的方法

// 推进一个VC (压栈操作)
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;

// 弹出导航控制器所管理的当前VC,返回值为弹出的视图控制器
- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated; 

// 弹出视图控制器,直到指定的在顶部。返回弹出的控制器。
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated; 

//  直到堆栈上只剩下一个视图控制器。返回弹出的控制器。
- (nullable NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated;

// 设置导航控制器所管理的VC 数组,如果动画是YES,那么根据新的top视图控制器是否先前在堆栈中模拟push或pop。
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated

UINavigationControllerDelegate

//即将展示视图控制器时调用
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
//已经展示视图控制器时调用
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
//屏幕旋转时 NavigationController 支持的方向
- (UIInterfaceOrientationMask)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(tvos);
//自控制器支持的方向
/** 子控制器支持的方向
 * UIInterfaceOrientation 枚举类型
 *  1. UIInterfaceOrientationUnknown 设备的朝向不能确定。
 *  2. UIInterfaceOrientationPortrait  该设备处于竖屏模式,设备保持直立,底部的Home键。
 *  3. UIInterfaceOrientationPortraitUpsideDown 该设备处于竖屏模式,但上下颠倒,设备保持直立,顶部的Home键。
 *  4. UIInterfaceOrientationLandscapeLeft 设备处于横向模式,设备保持直立,右侧Home键。
 *  5. UIInterfaceOrientationLandscapeRight 该设备处于横向模式,设备保持直立,左侧Home键。
 */
- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(tvos);
//自定义转场动画
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController API_AVAILABLE(ios(7.0));
//自定义转场动画
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC  API_AVAILABLE(ios(7.0));

常用的设置

想要改变Bar的背景颜色可以这样设置

self.navigationController.navigationBar.barTintColor = [UIColor redColor];

取消半透明效果

self.navigationController.navigationBar.translucent = NO;

改变NavigationBar的标题颜色 和 字体大小

NSDictionary *dic = [NSDictionary dictionaryWithObject:[UIColor blackColor]   forKey:NSForegroundColorAttributeName];
self.navigationController.navigationBar.titleTextAttributes = dic;

隐藏NavigationBar

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:YES animated:animated];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.navigationController setNavigationBarHidden:NO animated:animated];
}

想要改变NavigationBar的前景颜色 也就是所有UIBarButtonItem的字体颜色可以如下设置

self.navigationController.navigationBar.tintColor = [UIColor redColor];

单独设置

self.navigationItem.leftBarButtonItem.tintColor = [UIColor grayColor];

当tableView等滑动时是否隐藏NavigationBar

self.navigationController.hidesBarsOnSwipe = YES;

当视图接受点击时 是否隐藏NavigationBar

self.navigationController.hidesBarsOnTap = YES;

当键盘出现时是否隐藏NavigationBar

self.navigationController.hidesBarsWhenKeyboardAppears = YES;

当屏幕改变方向时是否隐藏NavigationBar

self.navigationController.hidesBarsWhenVerticallyCompact = YES;

当视图被push完之后 是否隐藏NavigationBar

self.navigationController.hidesBottomBarWhenPushed = YES;

UINavigationController的层级

我们创建一个简单的带UINavigationController的工程 看一下他们的层级 工具 Xcode11 模拟器iphone11

从层级我们能清楚的看到UINavigationBar(层级选中的状态)及下层的子控件是我们需要操作的单元,但是从官方给我们留出来的接口来看 我们很难拿到Bar的子控件。

上面的是最原始的Bar 我们可以加上一个标题再看一下.

我们可以看到登陆这个Label在Bar下的第一级子试图 而且在最上层 对原始状态的Bar下的视图除了遮挡没有产生任何影响

可以看到我们设置UINavigationBar的背景颜色是不会有效果的,因为其前面还有几个视图挡着Bar。

原文地址:https://www.cnblogs.com/huanying2000/p/13633987.html