標籤:
一、UINavigationBar的結構
導覽列幾乎是每個頁面都會碰到的問題,一般兩種處理方式:1.隱藏掉不顯示 2.自訂
1. 添加導覽列
TestViewController * mainVC = [[TestViewController alloc] init];UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:mainVC]; self.window.rootViewController = nav;
2. 隱藏導覽列
在的TestViewController.m檔案中,使用以下代碼:
- (void)viewDidLoad { [super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES]; //self.navigationController.navigationBar.hidden = YES;}
說明:通過屬性直接設定之所以能成功,是因為雖然navigationBar是readonly,但是hidden是預設的(readwrite)。建議使用第一個,通過發送訊息來設定。
3. 修改導覽列背景色
由於系統內建的導覽列已經不能滿足使用者的審美需求,因此開發中導覽列或多或少都被自訂了;即便只是修改了背景色或是字型顏色。
說明:為什麼能修改所有導覽列的背景色?
- 查看UINavigationBar發送的訊息appearance,是一個名為UIAppearance協議。根據官網解釋:UIAppearance是一個外觀協議(裝飾模式)。要想改變外觀需要實現此協議,因此UINavigationBar內部肯定實現了此協議。
- 查看標頭檔UIAppearance協議裡面有4個方法,但是根據官網文檔,iOS9以後有兩個方法被廢棄。因此只有下面兩個可用,都返回的是類的對象,因此可以給此類發送修改外觀的訊息.比如:setBarTintColor。其實這裡拿到對象後可以任意修改。
+ (instancetype)appearance;+ (instancetype)appearanceForTraitCollection:(UITraitCollection *)trait
在的TestViewController.m檔案中,使用以下代碼:
- (void)viewDidLoad { [super viewDidLoad]; // 無效果 self.navigationController.navigationBar.backgroundColor = [UIColor redColor]; // 可行 [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav.png"] forBarMetrics:UIBarMetricsDefault];}
說明:
- 下面代碼為什麼無效果,其實看一下結構圖就明白了。
self.navigationController.navigationBar.backgroundColor = [UIColor redColor];
UINavgationBar結構圖
沒錯:這樣修改的是navigationBar的背景色,而navigationBar裡面添加了UIView和UIImageView,UILabel等控制項,覆蓋了navigationBar。
- 那麼如何來修改?
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"yao_1"] forBarMetrics:UIBarMetricsDefault];
通過添加背景圖,使用預設的模式。
注意:這裡會出現狀態列背景色也變化的問題,其實這是由於在navigationBar添加的控制項自動延伸到邊界造成的。如果只是修改導覽列的背景色,完全沒必要再給navigationBar添加控制項了,給navigationBar堆太多的無用控制項,不能忍。
// 設定透明[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"yao_1"] forBarMetrics:UIBarMetricsCompact];// 修改navigationBar的背景色self.navigationController.navigationBar.backgroundColor = [UIColor redColor];
這樣修改navigationBar背景色,才有種很舒暢的感覺,有木有。因為我就只是要修改navigationBar的背景色而已麼。:
UINavgationBar
為什麼要這樣
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
或者為什麼要這樣
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"yao_1"] forBarMetrics:UIBarMetricsDefault];
UINavigationBar和UINavigationController、UIViewController關係
1.導覽列類名:UINavigationBar,是導航控制器(UINavgationController)下得一個屬性,一般給一個視圖控制器(TestViewController)添加導覽列,也就是把它添加為導航控制器(UINavgationController)的根視圖控制器。
2.在此視圖控制器中為什麼可以直接操作導航控制器,因為TestViewController類是自訂的繼承自UIViewController類的。而UIViewController類中有一個類別,聲明了UINavgationController類的一個屬性。在第一步的時候,把這個屬性設定為上面導航控制器的對象。
UIController分類
3.UINavigationBar對照圖如下:
UINavigationBar對照圖
UINavgationBar結構圖說明:
- 的對照關係可以看到,UINavigationBar包含一個:UINavigationBarBackground控制項(已經延伸到邊界,覆蓋掉了導覽列),另一個UINavigationBarBackIndicatorView(其實就是那個藍色的返回按鈕,當push進來一個ViewController才會顯示)
- UINavigationBarBackground控制項裡麵包含:UIBackdropView(UIBackdropEffectView標識陰影視圖),UIImageView
總結:
可以看到,UINavigationBarBackIndicatorView(返回按鈕只佔了左邊一部分地區,並且在push新的視圖控制器時才顯示。因此,顯示在最上面的是UIImageView)。所以,這才是通過代碼
self.navigationController.navigationBar.backgroundColor = [UIColor redColor];
*修改背景色,老是被遮住的根本原因。解決方案,因此掉UIImageView控制項,或者乾脆給UIImageView設定一張你想要的背景色的圖片。*
二、UINavigationBar的自訂1. 自訂
一般自訂分三種情況:左側、右側和中間視圖
- (void)viewDidLoad { [super viewDidLoad]; // 自訂導覽列左側按鈕 UIButton * leftBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; leftBtn.frame = CGRectMake(0, 7, 83, 30); leftBtn.backgroundColor = [UIColor orangeColor]; [leftBtn addTarget:self action:@selector(onTap) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem * leftItem = [[UIBarButtonItem alloc] initWithCustomView:leftBtn]; self.navigationItem.leftBarButtonItem = leftItem;}// 點擊事件處理- (void)onTap { NSLog(@"點擊了導覽列左側按鈕");}
自訂右側按鈕
和自訂左側按鈕方法類似,差別如下:
self.navigationItem.rightBarButtonItem = rightItem;
自訂中間視圖
UIView * centerView = [[UIView alloc] initWithFrame:CGRectMake(0, 7, 110, 30)];centerView.backgroundColor = [UIColor greenColor];self.navigationItem.titleView = centerView;
2. 結構分析
從自訂的代碼看到,自訂都是在修改navigationItem裡面的東西。查看標頭檔可知,TestViewController之所以可以操作navigationItem,和上面UINavigationController實現方式一樣。
UINavigationBar類中有一個items集合,儲存navigationItem和其他相關內容。UINavigationItem類裡面儲存leftBarButtonItems、rightBarButtonItems等集合。同時也會有leftBarButtonItem、rightBarButtonItem控制項,根據集合是否為空白來決定是否建立和顯示這些控制項。
因此,當不設定內容時,預設集合為空白,所有控制項也就不顯示。
3. 手寫代碼技巧
對於導覽列的自訂,大部分app都是左側為"返回",右側為"地圖",“掃碼”等按鈕,中間除顯示標題外,可能會自訂個分段按鈕,選擇菜單等。而對於這些自訂的按鈕和視圖,尺寸都是根據圖片尺寸和導覽列的寬高憑感覺設定的(總之,我以前是這樣>.<)。
今天在測試iOS7的布局使用了SB,發現控制項拖上去它會自適應系統給定的尺寸。然後我繫結控制項擷取了這些控制項的尺寸。測試了iPhone4s和iPhone6,擷取到的左側和右側按鈕尺寸:frame = {0,7,83,30},中間的視圖尺寸:frame = {0,7,110,30}。
這樣,以後導覽列按鈕沒有什麼特殊要求,就可以都按這個尺寸設定了。
原文連結:http://www.jianshu.com/p/b7818eba288c
iOS 自訂導覽列筆記