导航栏显示和隐藏的坑

作者: zhq1992 | 来源:发表于2016-06-20 12:10 被阅读6306次

    在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的下拉放大。

    代码下载地址

    点击进入Github

    相关文章

      网友评论

        本文标题:导航栏显示和隐藏的坑

        本文链接:https://www.haomeiwen.com/subject/tqovdttx.html