导航控制器以及导航栏学习笔记

本文详细介绍了iOS中的UINavigationController及其UINavigationBar组件的工作原理和配置方法,包括设置风格、背景图片、title样式,以及如何自定义Back按钮、修改返回指示图片和位置。同时也讨论了iOS11之后的变化及解决方案,并提到了设置prompt和toolBar的相关内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UINavigationViewController

使用苹果官方网站的架构图:
这里写图片描述

UINavigationViewController(下边简称UINaviVC)整体功能由3部分组成:UINaviVC本身, Bars(navigationBar,toolBar)和ViewControllers。UINaviVC作为管理者负责ViewController和Bar的交互。

具体说来就是UINaviVC从它的viewControllers中取得navigationItem对象,使用这个对象来更新Bar。如果Bar上发生了事件,比如Back按钮点击,UINaviVC作为Bar的Delegate来处理事件,比如弹出当前View Controller。

UINavigationBar

UINavigationBar继承自UIView,是UINaviVC顶部的Bar。苹果给出的UINavigationBar的组成部分是固定的,一般来讲我们不是通过addSubView的方式来构建UINavigationBar,而是使用UINavigationItem来构建UINavigationBar。

当然,既然UINavigationBar继承自UIView,我们也可以使用addSubView的方式给UINavigationBar添加子视图,但是需要自己管理布局。

UINavigationBar的组成部分:
这里写图片描述

UINavigationItem本身不是一个View,是一个继承自NSObject的对象,用来配置UINavigationBar上的界面。

UINavigationBar管理了一系列的UINavigationItem,以栈的形式,所以UINavigationBar上也有pushItem,popItem等API,如果我们使用UINaviVC,UINaviVC会替我们做这些管理。如果要自定义NavigationBar可能需要关注这些API。

所以,重复一遍:UINavigationBar的整体配置是通过UINaviVC的navigationBar属性来配置的,然后针对不同的UINaviVC的ViewController,进行更新。更新的依据就是ViewController的navigationItem属性。

几个例子:

设置风格

self.navigationController.navigationBar.barStyle = UIBarStyleBlack;

这里写图片描述

设置背景图片

UIImage *backgroundImg = [[UIImage imageNamed:@"barBackgroundImg"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

[self.navigationController.navigationBar setBackgroundImage:backgroundImg forBarMetrics:UIBarMetricsDefault];

这里写图片描述

调整title的上下位置:

[self.navigationController.navigationBar setTitleVerticalPositionAdjustment:8 forBarMetrics:UIBarMetricsDefault];

这里写图片描述

设置title的文字样式

NSDictionary * attrs = @{NSForegroundColorAttributeName:[UIColor yellowColor]};
self.navigationController.navigationBar.titleTextAttributes = attrs;

这里写图片描述

上述这些例子设置都是全局的,在任何一处设置了,以后的Bar就是一直这样。所以如果仅仅是一个ViewController界面需要改变这些属性,应该在viewWillAppear设置,然后viewDidDisappear中恢复原来的设置。

设置title
title的内容由Top Navigation Item的title属性来决定。Top ViewController的navigationItem的title属性默认值是ViewController的title,可以重新赋值覆盖。

self.navigationItem.title = @"我的Title";

上边的代码要在当前展示的ViewController中设置,之所以强调这个,是因为马上要介绍的back button是在上一个ViewController中做设置。

设置Back按钮
Back按钮的配置是由TopViewController的上一个ViewController的navigationItem决定的,具体的来说是navigationItem的back

UIBarButtonItem *backBtnItem = [[UIBarButtonItem alloc] init];
backBtnItem.title = @"返回Main";
self.navigationItem.backBarButtonItem = backBtnItem;

上述代码要在前一个ViewController中。

这里写图片描述

这里有几点说明:
1. 默认backBarButtonItem是nil,所以需要创建一个UIBarButtonItem,如果直接设置,由于OC语言的机制,不会报错,也不会生效。
2. 如果没有backBarButtonItem是nil,则NavigationBar默认的返回按钮显示返回的那个ViewController的title,但是,如果title太长放不下,就什么都不显示。但是如果创建了backBarButtonItem,但是没有给title赋值,那么NavigationBar什么都不显示,但是一旦赋值了backBarButtonItem的title,则不管多长都会显示。基本思想就是隐式设置的东西给一个合理的配置,程序员显示设置的不管是否合理,都去执行。
3. backBarButtonItem还有一个属性是image,如果设置了image,则不再显示title。
4. 创建backBarButtonItem的时候,不能使用initWithCustomView:初始化函数,因为NavigationBar不支持。

When configuring your bar button item, do not assign a custom view to it; the navigation item ignores custom views in the back bar button anyway.

修改返回指示图片(箭头)
修改返回箭头是一个整体的操作,需要在bar上设置

UIImage *backImg = [UIImage imageNamed:@"backBtn"];
self.navigationController.navigationBar.backIndicatorImage = backImg;
self.navigationController.navigationBar.backIndicatorTransitionMaskImage = backImg;

这里写图片描述

这里要注意的是一定同时设置backIndicatorTransitionMaskImage属性,否则不生效。

修改返回指示图片(箭头)的位置
更改back按钮返回指示图片的位置在iOS11之前有两种方式:制作一个有insets的图片或者使用leftBarButtonItem,代码分别如下:

//这段代码只能调整高度
UIImage *backImg = [UIImage imageNamed:@"backBtn"];
backImg = [backImg imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
backImg = [backImg imageWithAlignmentRectInsets:UIEdgeInsetsMake(0, 0, -3, 0)];

self.navigationController.navigationBar.backIndicatorImage = backImg;
self.navigationController.navigationBar.backIndicatorTransitionMaskImage = backImg;
//注意:和backBarButtonItem不同,leftBarButtonItem是当前页面的属性,所以要在当前显示的ViewController中设置。
//并且leftBarButtonItem没有默认的响应函数,需要自己写pop的事件。
UIImage *backImg = [UIImage imageNamed:@"backBtn"];
UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithImage:backImg style:UIBarButtonItemStylePlain target:self action:@selector(clickLeftItem)];

self.navigationItem.leftBarButtonItem = leftItem;

iOS11失效的原因:https://forums.developer.apple.com/thread/80075
简单的说来就是iOS11在NavigationBar中增加了图层,写死了约束(至少没放开修改)。导致我们自己对位置的调整不能随心所欲。

对于iOS11,有两种办法解决:一是使用addSubview的方式添加按钮,自己管理布局和事件响应;二是彻底重写NavigationBar。但是对于已有的功能,上述两种方法代价都不小。

针对已有的代码,这篇文章给出了解决方案。思路就是研究Apple的图层然后修改布局。但是如果系统的升级对图层又有修改,会有问题。对于这一点应该密切注意系统的升级。

为了方式上述链接失效,再贴一篇

设置prompt:
这是一个不常见的功能

self.navigationItem.prompt = @"hello, 大家好";

效果如下:
这里写图片描述
除非每一个界面都有prompt,否则导航栏高度会变化,效果不太好。

设置toolBar
toolBar默认是隐藏的,需要主动的显示出来。

UIView *toolBarCustomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400,30)];
toolBarCustomView.backgroundColor = [UIColor blueColor];
UIBarButtonItem *barBtnItem = [[UIBarButtonItem alloc] initWithCustomView:toolBarCustomView];
[self.navigationController setToolbarHidden:NO];
self.toolbarItems = @[barBtnItem];

这里写图片描述

常见的评论栏,如果效果是点击评论栏进入新页面评论,那就可以考虑用toolbar来做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值