UINavigationBar和UINavigationItem
今天修复了一个小bug, 由于一个viewController的右边有3个按钮,在手机上和中间的title离得有点近了. 大致是这样 , 按钮是随便写的 , 没加图????,
通过这样设置的 self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView: rightView]; rightView是一个普通的UIView,上面放了3个button ,
既然右边按钮距离中间的title太近了, 而且 "更多" 右边还有一点小空隙 , 就想改变rightBarButtonItem距离右边的距离,让3个按钮往右挤挤,大致是做成这样的.
好了, 现在知道了现状,也知道的目的.那就开始做了.
一开始的想法是 通过加一个UIBarButtonSystemItemFixedSpace的item,把这个设置为负值,这样就可以把rightView右移了, 代码大致是这样
UIBarButtonItem *negativeSpacer = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
target:nil action:nil];
/**
* width为负数时,相当于btn向右移动width数值个像素,由于按钮本身和边界间距为5pix,所以width设为-5时,间距正好调整
* 为0;width为正数时,正好相反,相当于往左移动width数值个像素
*/
negativeSpacer.width = -5;
self.navigationItem.rightBarButtonItems = @[negativeSpacer, rightView, ];
可惜,理想很美好,现实很骨感, 把 negativeSpacer.width 设置成一个正值倒是挺管用的 ; 设置为-20, 一点变化也没有 , 估计是在iOS的某次更新后系统做了处理了 , 好吧,下一条路.
第二种思路 , UIBarButtonItem 里面的文档看了好久 , UIBarButtonItem都不是UIView的子类 , 没有可以设置边距的东西 , 后面甚至想到了重写 navigationController的viewDidLayoutSubviews , 在那里面重写设置frame, 但是想想这个影响的页面太多了,判断会很多 , 也不太能拿到 这个rightView , 得不偿失.
就在失望之际 , 发现了UINavigationBar *navigationBar , 这是UIView的一个子类, 或许可以在这个上面动动手脚 , 于是
UIView * rightView = [[UIView alloc] initWithFrame:CGRectMake(Screen_Width-130, 0, 130, 44)];
[rightView addSubview:videoButton];
[rightView addSubview:micButton];
[rightView addSubview:moreBtn];
[self.navigationController.navigationBar addSubview:rightView];
运行之后 , 果然变成了想要的样子. 右边贴边了 , 而且想设置多少就是多少, 美滋滋.
但是在pop的时候发现了一个问题 , 已经pop到上一个界面了, 但是这3个按钮没有消失 , 只要将信将疑的在viewWillDisappear里 , 把[rightView removeFromSuperview] , 事实果然有效, pop之后, 这3个按钮也消失了. nice.
虽然功能完成了,但是UINavigationBar和UINavigationItem是什么关系呢? 自然要一探究竟.
一、导航条navigation bar
1、导航条navigationbar属于导航控制器,一个导航控制器只有一个导航条。
2、在一个导航控制器push新页面和pop页面时,导航条是同一个。
3、在一个视图控制器内改变了导航条的样式,其它控制器的导航条的样式也会改变,也说明了导航条属于导航控制器,而不是每个视图控制器都有一个导航条。
4、导航条的层级结构
navigationbar层级
UINavigationBar
UIBarBackground
UIBarBackground视图是比UINavigationBar视图要大
二、导航栏与self.view布局问题
iOS开发过程当中遇到导航栏遮挡布局的问题,在页面跳转后,下级页面也会被导航栏所遮挡。
如果你的容器是UINavigationController,在iOS7之前导航栏默认为半透明的,布局默认会从顶部开始,所以会被遮挡。
解决方案1:
在iOS7 UIViewController引入了一个新的属性edgesForExtendedLayout,默认为UIRectEdgeAll,即铺满整个屏幕
self.edgesForExtendedLayout =UIRectEdgeNone;设置后布局从导航栏下开始
解决方案2:
self.navigationController.navigationBar.translucent =NO;
将导航栏设置为不透明后,布局会自动放到导航栏以下。
三、导航栏与self.view高度问题
在带有导航栏的控制器中,viewDidLoad方法执行前后self.view的高度是不一致的,执行前为屏幕的高度,而执行后则减去导航栏+状态栏的高度。
//以iphone6为例
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"执行前%d",CGRectGetHeight(self.view.frame));
}
- (void)viewDidAppear:(BOOL) animated{
[super viewDidLoad];
NSLog(@"执行后%d",CGRectGetHeight(self.view.frame));
}
log:
执行前667
执行前603
准确说应该是viewWillAppear和viewDidAppear之间self.view高度发生变化
在viewWillAppear时视图控件布局还没有设置,因此对于一个VC,self.view就是最原始的状态,从屏幕顶端开始,高度为ScreenHeight
在viewDidAppear时视图已经显示在屏幕上了,self.view以及子视图的布局已经设置好了,而self.view由于导航栏不透明或其他原因,其布局是从导航栏下方开始到屏幕底部,高度为ScreenHeight-64,64为导航栏(44)+状态栏(20)高度
四、navigationBar与navigationItem
1、navigationbar继承自UIView,通常是位于屏幕顶端的控件。
2、navigationbar是navigationitem的容器,以stack的形式管理UINavigationitem。需要说明的是UInavigationbar属于导航控制器,且只有一个,navigationitem是独立存在的不属于导航控制器也不属于导航条,它是视图控制器的属性,每一个viewController都有一个navigationitem。navigationbar提供了多种方法来管理单个和多个navitionItem。
3、UINavigationitem也是容器。包括titleView 、左侧N个UIBarButtonItem,右侧N个UIBarButtonItem这些控件,并提供了方法来管理这些控件。
总结 , navigationBar与navigationItem关系 , 可以类比 navigationController 与 viewcontroller,
navigationItem 与 titleView , leftBarButtonItem 的关系, 可以类比 self.view 与 view上的子控件 .
NSLog(@"topItem %@",self.navigationController.navigationBar.topItem);
NSLog(@"items %@",self.navigationController.navigationBar.items);
topItem <UINavigationItem: 0x102865e80> title='订单详情' leftBarButtonItems=0x2803a00f0
items [
第0个 -- <UINavigationItem: 0x102808640> title='热门' titleView=0x101f4d400
第1个 -- <UINavigationItem: 0x1028ccb00> title='项目订单' leftBarButtonItems=0x2803aa430
第2个 -- <UINavigationItem: 0x102865e80> title='订单详情' leftBarButtonItems=0x2803a00f0
https://www.jianshu.com/p/a7d5078e31db
上一篇: lua对接bmob数据库
下一篇: iOS 打开文件APP,从文件中读取
推荐阅读
-
ubuntu16.04下Caffe绘制训练过程的loss和accuracy曲线
-
关于过度绘制和渲染的介绍
-
【虚拟环境】4、基于virtualenv和virtualenvwrapper的虚拟环境使用
-
SwiftUI 2.0 LazyVGrid和LazyHGrid 深入使用教程含源码
-
iOS使用YYLabel 点击展开和收起全文
-
UINavigationBar和UINavigationItem
-
iOS willMoveToParentViewController和didMoveToParentViewController使用
-
css3动画:transition和animation
-
SwiftUI NavigationView和List的使用
-
编写程序,包括一个标签、一个文本框和一个按钮,当用户单击按钮时,程序把文本框中的内容复制到标签中。