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。