NavigationController已經(jīng)洗干凈了,就等你來(lái)

好久沒(méi)有更新博客了,近日把項(xiàng)目中遇到的NavigationController 相關(guān)技術(shù)點(diǎn)梳理一下,與大家共同分享

首先來(lái)點(diǎn)基礎(chǔ)的屬性

一. 基本屬性

  • 設(shè)置顏色
    如果項(xiàng)目中 Navigation 都是統(tǒng)一的,而你又懶得單獨(dú)抽取一個(gè)BaseNavigationController,可以直接在 [appDelegate didFinishLaunchingWithOptions]方法中寫(xiě)
//設(shè)置NavigationBar背景顏色
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];

// 通過(guò)富文本設(shè)置title 樣式(這里也可以通過(guò)自定義Label,然后設(shè)置 titleView 來(lái)實(shí)現(xiàn))
[[UINavigationBar appearance] setTitleTextAttributes:@{
                    NSForegroundColorAttributeName : [UIColor whiteColor]
                                                           }];

// 設(shè)置狀態(tài)欄格式,如果 NavigationBar 為深色調(diào),就設(shè)置為 UIBarStyleBlack,則狀態(tài)欄顯示為白色
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
  • 實(shí)現(xiàn) NavigationBar 透明效果
    實(shí)現(xiàn)透明可能大家第一個(gè)想到的是 設(shè)置 alpha 值,但是由于設(shè)置了作為父控件的 NavigationBar 的透明度后,其子控件 BarButtonItem 也會(huì)隨之改變,因此想要實(shí)現(xiàn)導(dǎo)航欄透明,但是 BarButtonItem 正常顯示(類(lèi)似 手機(jī)QQ 的好友動(dòng)態(tài)頁(yè)),可以采用下面的方法
// 設(shè)置一個(gè)空的圖片背景圖片,就能實(shí)現(xiàn)導(dǎo)航欄透明但是 BarButtonItem 正常顯示
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
                                                forBarMetrics:UIBarMetricsDefault];

然而設(shè)置之后乍一看沒(méi)問(wèn)題,可仔細(xì)一看你會(huì)發(fā)現(xiàn)NavigationBar下面還有一條細(xì)線(xiàn),這個(gè)細(xì)線(xiàn)就是shadow


快看那條淡淡的細(xì)線(xiàn)!

層級(jí)關(guān)系圖

可通過(guò)以下代碼來(lái)去掉

// 設(shè)置一個(gè)空的 shadowImage 來(lái)實(shí)現(xiàn)
self.navigationController.navigationBar.shadowImage = [UIImage new];

那么有同學(xué)可能要問(wèn)了,一直透明的可以通過(guò)上述方法來(lái)實(shí)現(xiàn),那如果想要隨著 上拉距離的改變,實(shí)現(xiàn)其透明度動(dòng)態(tài)變化要怎么做?

// 這個(gè)就要監(jiān)聽(tīng) scrollView 的 offset
// 然后獲取到 NavigationBar復(fù)合視圖 的顯示子控件,動(dòng)態(tài)改變其透明度
[[self.navigationController.navigationBar subviews] objectAtIndex:0].alpha = 0;

既然講到這里了就說(shuō)下來(lái)回 push 或 pop,以及使用手勢(shì)來(lái)返回的時(shí)候,上下層級(jí)之間 NavigationBar 隱藏與否的設(shè)置,因?yàn)槿绻@里沒(méi)處理好的話(huà),會(huì)有一個(gè)黑條,或者直接顯示下一層級(jí)的視圖,體驗(yàn)特別差,這時(shí)候就需要通過(guò)動(dòng)畫(huà)的方式的在下一層級(jí)進(jìn)行設(shè)置

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // 當(dāng)前 VC 需要顯示 navigationBar 就設(shè)置為 NO,需要隱藏就設(shè)置為 YES
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}
  • 側(cè)滑手勢(shì)相關(guān)
    很多時(shí)候,leftBarButtonItem需要自定義,因?yàn)槟J(rèn)的顯示上一層級(jí)的title不一定是我們想要的,但是自定義改變之后,會(huì)發(fā)現(xiàn)側(cè)滑返回的手勢(shì)不好使了


#warning 這時(shí)候就需要在當(dāng)前 VC 中設(shè)置手勢(shì)代理了
self.interactivePopGestureRecognizer.delegate = self;

// 實(shí)現(xiàn)代理方法:返回 YES,則手勢(shì)有效
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    //當(dāng)導(dǎo)航控制器的子控制器個(gè)數(shù) 大于1 手勢(shì)才有效
    return self.childViewControllers.count > 1;
}
  • 由于項(xiàng)目中同一個(gè) VC,有時(shí)候是 modal 出來(lái)的,有時(shí)候是 push 出來(lái)的,那么在這個(gè)VC中就要判斷進(jìn)行處理
NSArray *viewcontrollers=self.navigationController.viewControllers;
if (viewcontrollers.count > 1) {
    if ([viewcontrollers objectAtIndex:viewcontrollers.count - 1] == self) {
        // push方式
        [self.navigationController popViewControllerAnimated:YES];
    }
} else {    
    // present方式    
    [self dismissViewControllerAnimated:YES completion:nil];
}
  • 如果要實(shí)現(xiàn)如下效果的導(dǎo)航欄,設(shè)置 leftBarButtonItems 和 rightBarButtonItems 即可


    喂!焦點(diǎn)在 NavigationBar,老看 tableView 干啥!
  • 關(guān)于 rootVC 的 offset,先來(lái)看幾個(gè) ViewController 的屬性


  • iOS7以后默認(rèn)設(shè)置是 UIRectEdgeAll,translucent 的默認(rèn)值是 true,這個(gè)組合會(huì)使 rootView 的布局從 (0, 0) 開(kāi)始,就會(huì)造成 rootView 被 NavigationBar 遮擋住一部分,將 edgesForExtendedLayout 設(shè)置為 UIRectEdgeNone 即可解決問(wèn)題

  • automaticallyAdjustsScrollViewInsets 默認(rèn)值是 YES,表示在全屏下會(huì)自動(dòng)將 第一個(gè)添加到 rootVC 的 ScrollView 的 contentInset 設(shè)置為 (64, 0, 0, 0),這樣 scrollView 就不會(huì)被導(dǎo)航欄遮擋住了

二. 來(lái)回跳轉(zhuǎn)

項(xiàng)目中有個(gè)需求是A push 到 B, B push 到 C, C pop 到 D,D 再 pop到 A,就好比這樣:

類(lèi)似這種交叉跳轉(zhuǎn)的感覺(jué)
  • 首先 A push 到 B,直接使用
[self.navigationController pushViewController:B animated:YES];
// 此時(shí) self.navigationController.childViewControllers = [A, B];
  • 然后 B push 到 C,同理
[self.navigationController pushViewController:C animated:YES];
// 此時(shí) self.navigationController.childViewControllers = [A, B, C];
  • 現(xiàn)在要實(shí)現(xiàn) C pop 到 D,由于 navigationController.childViewControllers 是只讀的,因此不能直接對(duì)其進(jìn)行操作


    navigationController.childViewControllers 是只讀的
// 建立可變拷貝對(duì)象,然后進(jìn)行替換操作
NSMutableArray *navChildMArr = [self.navigationController.childViewControllers mutableCopy];
[navChildMArr replaceObjectAtIndex:1 withObject:D];

// 當(dāng)然,最后再將替換后的數(shù)組賦值回去不要忘了
[self.navigationController setViewControllers:navChildMArr animated:YES];

#warning 至于寫(xiě)上面這串代碼的時(shí)機(jī):寫(xiě)在 B push C 之后可以,寫(xiě)在 C 的 viewDidLoad() 方法中也可以

最后的效果如圖

對(duì),效果如圖
就四這么簡(jiǎn)單!

如果有其他問(wèn)題,可以在留言處寫(xiě)下來(lái),不定期更新

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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