今天修復了一個小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