iOS 自定義導航欄筆記


一、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] setBarTintColor:[UIColor redColor]];

    效果圖

說明:為什么能修改所有導航欄的背景色?

  1. 查看UINavigationBar發送的消息appearance,是一個名為UIAppearance協議。根據官網解釋:UIAppearance是一個外觀協議(裝飾模式)。要想改變外觀需要實現此協議,因此UINavigationBar內部肯定實現了此協議。
  2. 查看頭文件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]; }

說明:

  1. 下面代碼為什么無效果,其實看一下結構圖就明白了。
self.navigationController.navigationBar.backgroundColor = [UIColor redColor];

UINavgationBar結構圖

沒錯:這樣修改的是navigationBar的背景色,而navigationBar里面添加了UIView和UIImageView,UILabel等控件,覆蓋了navigationBar。

  1. 那么如何來修改?
[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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM