1. 程式人生 > >導航欄顯示和隱藏的坑

導航欄顯示和隱藏的坑

在iOS開發中,經常需要從一個無NavigationBar的控制器push到一個有NavigationBar的控制器,或者相反。看似只要設定一下NavigationBar的Hidden屬性就可以了,其實裡面還有不少坑。

隱藏導航欄的方法很簡單,只要在控制器將要出現的時候設定NavigationBar隱藏就可以了,然後在控制器將要消失的時候重新顯示NavigationBar,效果如圖1所示。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // 隱藏導航欄方法1
    self
.navigationController.navigationBarHidden = YES; // 方法2 // [self.navigationController setNavigationBarHidden:YES]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.navigationController setNavigationBarHidden:NO]; }

圖1.gif


但是仔細觀察會發現切換的過程並不順滑:1.有導航欄的控制器出現時,導航欄會立即出現,而控制器的View是自右向左漸入的(簡書其實就是這樣的);2.點選返回按鈕時,導航欄消失且右側會出現黑邊。如圖2所示。


圖2.gif


因為在push頁面的時候,animated屬性是設定成YES的,所以控制器View的出現會有動畫。animated屬性通常都是設定成YES的,這樣的頁面切換會讓人比較舒服。

[self.navigationController pushViewController:[[HQThirdViewController alloc] init] animated:YES];

所以我們猜想一下,導航欄的顯示和隱藏是不是也應該有個animated屬性。果不其然,設定導航欄隱藏還有另一個方法可以開啟和關閉動畫,我們開啟動畫之後再看看效果,如圖3。

- (void)viewWillAppear:
(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController setNavigationBarHidden:YES animated:YES]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.navigationController setNavigationBarHidden:NO animated:YES]; }

圖3.gif

導航欄的顯示和控制器的View顯示都有動畫了,pop的時候也不會出現黑邊了。這個animated屬性官方是這樣解釋的:If animated, it will transition vertically using UINavigationControllerHideShowBarDuration. 意思就是說如果開啟動畫,導航欄會以某個時長進行垂直過渡。

對於UINavigationControllerHideShowBarDuration官方文件也給出瞭解釋:This variable specifies the duration when animating the navigation bar. Note that this is a constant value, so it cannot be set. 就是說UINavigationControllerHideShowBarDuration決定了導航欄動畫的時長,注意這是一個常量,不能被改變。

這樣就完美解決了嗎?不,另一個坑出現了。點選TabBarItem進入"我的"頁面的時候,導航欄也出現了動畫,因為動畫只能寫在ViewWillAppear方法裡,所以每次顯示頁面都會呼叫。


圖4.gif

現在這種情況下,animated屬性肯定是不能開啟的,但是pop時候的黑邊問題又該怎麼解決?

解決方法1
首先想想為什麼pop的時候導航欄直接就消失了,因為專案中我把導航欄的translucent屬性關閉了(這個屬性預設是開啟的),控制器的View不會有穿透效果,而pop的時候導航欄隱藏又沒有開啟動畫效果,所以就導致了導航欄直接消失。那麼我們再來看看開啟translucent屬性的效果,如圖5。


圖5.gif

黑邊不會再出現了,導航欄依舊是立即消失,但是控制器的View填充了整個畫面。這是一種解決方法,大家可以看看釘釘iOS客戶端,從設定頁面pop回我的頁面也是這種效果。

最後,如果希望Pop的時候導航欄不會立即消失而且沒有黑邊,切換TabBarItem的時候又不會出現動畫,那麼依舊還是要開啟animated屬性的。

解決方法2

1.給"我的"控制器.h檔案裡新增一個關閉動畫的屬性

@interface HQMineViewController : UITableViewController

@property (nonatomic, assign) BOOL closeAnimating;

@end

2.在自定義的TabBarController裡面實現UITabBarControllerDelegate,並實現如下方法

@interface HQTabBarController ()<UITabBarControllerDelegate>

@end

@implementation HQTabBarController

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    UINavigationController *navigationController = (UINavigationController *)viewController;

    if ([navigationController.topViewController isKindOfClass:[HQMineViewController class]])
    {
        HQMineViewController *mineVc = (HQMineViewController *)navigationController.topViewController;
        // 點選TabBarItem進入"我的"控制器 會關閉導航欄消失的動畫
        mineVc.closeAnimating = YES;
    }
    return YES;
}

}

3.修改"我的"控制器中隱藏導航欄的方法

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self.navigationController setNavigationBarHidden:YES animated:!self.closeAnimating];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self.navigationController setNavigationBarHidden:NO animated:YES];

    // 控制器消失時要開啟動畫,保證由其他方式進入控制器會有動畫
    self.closeAnimating = NO;
}

4.最終效果如圖6所示


圖6.gif

解決方法3
走了這麼多的彎路,接下來就放出最終解決方法了,其實只要將animated屬性繼承ViewWillAppear(Disappear)的animated屬性即可,恍然大悟。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self.navigationController setNavigationBarHidden:YES animated:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self.navigationController setNavigationBarHidden:NO animated:animated];
}

總結

方法3最簡單,又能完美解決NavigationBar顯示和隱藏切換的問題,順便簡單地實現了tableHeaderView的下拉放大。

程式碼下載地址