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

 

发布了91 篇原创文章 · 获赞 31 · 访问量 22万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章