UINavigationController詳解

1 概述

UINavigationController繼承自UIViewController,是一個(gè)基于棧的容器型控制器。既然是容器,它就能裝一些東西,比如UIView能裝各種組件(UILabel,UIButton等),UINavigationController裝的是視圖控制器。

一個(gè)UINavigationController包含了幾個(gè)部分,

  • Navigation Stack導(dǎo)航棧,它以棧的形式來管理視圖控制器。棧的一個(gè)視圖控制器(棧底),稱為根視圖控制器,其他稱為子視圖控制器。棧中的控制器可以通過self.navigationController找到UINavigationController的實(shí)例。

  • UINavigationBar導(dǎo)航條,棧中的視圖控制默認(rèn)會(huì)在頂部加一個(gè)導(dǎo)航條,雖然Navigation Bar顯示在子視圖控制器的界面上,但是它是由UINavigationController實(shí)例管理的,不過,導(dǎo)航條的內(nèi)容卻是由子視圖控制器決定(通過self.navigationItem設(shè)置)。

  • UIToolbar工具欄,UINavigationController在子視圖的底部提供了工具欄,默認(rèn)不顯示,也很少用到。

2 Navigation Stack導(dǎo)航棧

UINavigationController的作用是以棧的方式管理UIViewController,所以方法基本上是圍繞進(jìn)出棧的。

  • 進(jìn)棧方法

    當(dāng)子視圖控制器拿到UINavigationController的實(shí)例引用后,使用下列方法推控制器進(jìn)棧:

    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
    

    上面的進(jìn)棧方法是最常用的,它將當(dāng)個(gè)viewController推入棧中,如果要一次性設(shè)置多個(gè)viewController進(jìn)棧,可以使用下面的方法:

    - (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated
    

    因?yàn)閁INavigationController在一個(gè)時(shí)刻只能顯示一個(gè)視圖控制器,當(dāng)設(shè)置了多個(gè)viewController時(shí),顯示棧頂?shù)囊晥D控制器。

  • 出棧方法

    - (UIViewController *)popViewControllerAnimated:(BOOL)animated; 
    - (NSArray<UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
    - (NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated; 
    

    UINavigationController有3中出棧方式,第一個(gè)是移除當(dāng)前的子視圖控制器,第二個(gè)是返回到指定的子視圖控制器,UINavigationController會(huì)移除目標(biāo)控制到棧頂之前的所有視圖控制器。第三個(gè)是返回到棧底(根視圖控制器)。

3 導(dǎo)航欄顯示與隱藏

導(dǎo)航欄顯示與否是UINavigationController控制的,NavigationController提供了如下方法顯示與隱藏導(dǎo)航欄。

- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated; 

4 UINavationBar 導(dǎo)航條

導(dǎo)航條比較特別,它的創(chuàng)建,配置和顯示是由UINaviagtionController負(fù)責(zé)的,而內(nèi)容是由子視圖控制器提供的,具體是navigationItem。

4.1 導(dǎo)航條內(nèi)容定制

導(dǎo)航條的內(nèi)容是由當(dāng)前子視圖控制器的navigationItem屬性確定的,內(nèi)容主要分為左邊項(xiàng),標(biāo)題項(xiàng)以及右邊項(xiàng)。

4.1.1 左邊按鈕定制

除了根視圖控制器,在棧中的其他子視圖控制器中,導(dǎo)航條的左邊存在一個(gè)返回按鈕,定制這個(gè)按鈕的規(guī)則如下:

  • 如果當(dāng)前棧頂?shù)囊晥D控制器定義了navigationItem.leftBarButtonItem屬性,則以當(dāng)前定義的為準(zhǔn)。
  • 否則,如果上一個(gè)視圖控制器定義了navigationItem.backBarButtonItem屬性,則以上一個(gè)視圖控制器定義的為準(zhǔn)
  • 如果當(dāng)前視圖控制器為定義leftBarButtonItem屬性,上一個(gè)視圖控制器也沒有定義backBarButtonItem。則以上一個(gè)視圖控制器的title屬性為準(zhǔn)

navigationItem還有一個(gè)屬性是leftBarButtonItems,它允許用戶定義一個(gè)按鈕集合放在導(dǎo)航條的左邊。

4.1.2 標(biāo)題定制

UINavigationController根據(jù)下面的順序更新導(dǎo)航欄的標(biāo)題項(xiàng):

  • 棧頂視圖控制器使用navigationItem.titleView自定義標(biāo)題時(shí),優(yōu)先使用titleView
  • 否則,導(dǎo)航欄標(biāo)題使用一個(gè)UILabel作為標(biāo)題,內(nèi)容從視圖控制器的title屬性中獲取。

titleView是UIView的實(shí)例,也就是說標(biāo)題可以是任意UIView的子類,上面的UILabel也是UIView的子類。

4.1.3 右邊按鈕定制

棧頂視圖控制器設(shè)置了navigationItem.rightBarButtonItem時(shí),UINavigationController會(huì)將其設(shè)置內(nèi)容更新在導(dǎo)航欄的右邊,如果沒有設(shè)置,則在導(dǎo)航欄的右邊不顯示任何內(nèi)容。

leftBarButtonItem、rightBarButtonItem以及backBarButtonItem都是UIBarButtonItem類型的。也就是說,如果我們要在導(dǎo)航條上定義按鈕,就得使用UIBarButtonItem對象,如果系統(tǒng)提供的UIBarButtonItem的屬性滿足不了我們的需求,可以使用UIBarButtonItem.customView屬性來包裹我們指定的視圖。

4.2 導(dǎo)航欄的外觀定制

導(dǎo)航欄的外觀定制有兩種方式,一種是通過navigationBar的實(shí)例定制,另一種是通過UIAppearance來獲取實(shí)例類的外觀代理對象定制外觀,UIAppearance是一個(gè)協(xié)議(Protocol),實(shí)現(xiàn)了這個(gè)協(xié)議的類可以通過它的appearance方法獲取這個(gè)類的外觀代理,UIView已經(jīng)實(shí)現(xiàn)了這個(gè)協(xié)議。通過UIAppearance外觀代理類設(shè)置的外觀是全局性的。

4.2.1 BarStyle導(dǎo)航條樣式

導(dǎo)航欄默認(rèn)有兩種標(biāo)準(zhǔn)的顯示樣式:白底黑字和黑底白字,可以通過navigationBar.barStyle屬性設(shè)置。

//把a(bǔ)pp中的所有導(dǎo)航條都設(shè)置為黑底白字
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

//把myNavController下的導(dǎo)航條設(shè)置為黑底白字的樣式,其他navigationController中的不會(huì)改變
[myNavController.navigationBar setBarStyle:UIBarStyleBlack]

4.2.2 translucent 透明度

導(dǎo)航條默認(rèn)是半透明的(translucent),可以設(shè)置起為不透明,

[[UINavigationBar appearance] setTranslucent:NO];

需要注意的是,translucent=YES時(shí),子視圖控制器的self.view的原點(diǎn)在整個(gè)屏幕中的位置是導(dǎo)航欄的左上方(這個(gè)好理解,因?yàn)閷?dǎo)航欄是透明的,有點(diǎn)像css的絕對定位,所以控制器的view會(huì)頂上去,那么原點(diǎn)的位置就發(fā)送了變化),當(dāng)translucent=NO時(shí),控制器的self.view的原點(diǎn)在屏幕中的位置在導(dǎo)航欄的左下方。

當(dāng)translucent=YES時(shí),可設(shè)置控制器的edgesForExtendedLayout屬性來改變view的原點(diǎn)在屏幕中的位置

//從navigationBar下面開始計(jì)算一直到屏幕tabBar上部
self.edgesForExtendedLayout = UIRectEdgeNone;
//從屏幕邊緣計(jì)算(默認(rèn))
self.edgesForExtendedLayout = UIRectEdgeAll; 
//navigationBar下面開始計(jì)算一直到屏幕tabBar上部
self.edgesForExtendedLayout = UIRectEdgeTop;
//從navigationBar下面開始計(jì)算一直到屏幕底部
self.edgesForExtendedLayout = UIRectEdgeBottom;

4.2.3 導(dǎo)航欄的字體與顏色

導(dǎo)航欄的字體與顏色分別由以下幾個(gè)屬性控制:

導(dǎo)航欄字體與顏色
  • barTintColor 導(dǎo)航欄背景色,前面我們說了,barStyle有兩種樣式白底和黑底,如果設(shè)置了barTintColor的值,這個(gè)值會(huì)覆蓋barStyle設(shè)置的背景色。

    //設(shè)置導(dǎo)航欄的背景色
    [[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
    
  • tintColor 按鈕顏色

    //按鈕顏色
    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
    
  • titleTextAtrributes 標(biāo)題的樣式,通過NSAttributedStringKey查看可設(shè)置的屬性

     NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor blackColor],
                            NSForegroundColorAttributeName,
                            [UIFont boldSystemFontOfSize:18.0],
                            NSFontAttributeName,nil];
     [UINavigationBar appearance].titleTextAttributes = dic;
    

4.2.4 導(dǎo)航欄透明

是導(dǎo)航欄完全透明可以設(shè)置背景圖片和陰影圖片兩個(gè)屬性。按照業(yè)務(wù)需求,一般只有個(gè)別的頁面要求導(dǎo)航欄透明,所以這不使用全局設(shè)置,而在具體的ViewController中設(shè)置

[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
                                              forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
//通常導(dǎo)航欄透明,需要上移self.view原點(diǎn)的位置,這里還設(shè)置了translucent
self.navigationController.navigationBar.translucent = YES;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容