美文网首页iOSiOS技术资料iOS开发常用知识点
iOS NavigationBar颜色、透明度、隐藏设置探究

iOS NavigationBar颜色、透明度、隐藏设置探究

作者: CaffreySun | 来源:发表于2017-03-01 21:46 被阅读4633次

    一、在项目开发中NavigationBar设置遇到的坑

    在平时的开发中,我们往往会遇到这样的需求,两个ViewController的NavigationBar颜色不同、透明度不同或者有的隐藏有的不隐藏,当两个ViewController进行push或pop操作时,那么你可能会看到下面现象:

    • 两个ViewController的NavigationBar颜色不同,push/pop时颜色切换不和谐。 push/pop颜色切换不和谐push/pop颜色切换不和谐
    • 两个ViewController的NavigationBar隐藏设置不一样,push/pop时隐藏NavigationBar切换不和谐。 push/pop时隐藏NavigationBar切换不和谐push/pop时隐藏NavigationBar切换不和谐

    很丑有木有O(≧口≦)O,强迫症接受不了有木有O(≧口≦)O。
      导致出现上述问题的原因是navigationBar只有一个,改变navigationBar样式一定会影响其他ViewController的显示。

    二、寻找解决方案

    隐藏与显示的bug解决比较简单,因为苹果已经做好了,出现上述问题的原因是,没有使用对的方法。
      隐藏NavigationBar苹果提供了两个方法:[navigationController setNavigationBarHidden:]和[navigationController setNavigationBarHidden:animated:]。第一个方法无动画隐藏navigationBar,第二个方法可以控制是否动画隐藏navigationBar。解决上述bug只需如下代码:

    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        [self.navigationController setNavigationBarHidden:NO animated:animated];
        //不要使用下面方法,下面方法会导致隐藏和不隐藏的viewController转场时出现bug
        //    [self.navigationController setNavigationBarHidden:NO];
    }
    

    OK,隐藏与显示的bug解决了。效果如下:


    正确的使用方法解决bug正确的使用方法解决bug

    下面解决颜色的问题。在很多的APP都可以看到不同颜色的navigationBar的转场,但这些APP都完美的解决了颜色问题,比如微信。所以就要看看微信是如何处理的呢,这个时候就用到了一个款神奇,Mac软件Reveal,它可以看到在手机中安装的APP页面层级,至于如何使用请移步:使用Reveal查看任意App的技巧
      通过Reveal看到了微信的页面层次,如下图

    微信截图微信截图
      观察微信的层级发现,微信的navigationBar是透明的,ViewController顶部有一个view来充当navigationBar背景色,如上图左右两边的发现ViewController和小程序ViewController的顶部都有一个view,左边是黑字的右边是白色的,这样每个viewController的navigationBar的背景色就可以单独设置。

    三、有了指导方向,开始动手搬砖

    解决方法好像很简单,只需要在viewController.view的顶部加上一个barBgView就可以了(内心暗喜:这种代码我两分钟就可以敲完,啊哈哈哈ψ(`∇´)ψ)。
      那么开始战斗吧,啊哈哈! 哈利路亚!德玛西亚!赐给我码神的力量吧ヽ(`Д´)ノヽ(`Д´)ノヽ(`Д´)ノ!
      战斗没开始就发现遇到了坑,难道我要每个viewController里都写一遍加入barBgView的代码?不行viewController太多写起来太累;那写一个继承自viewController的父类,然后让所有viewController继承父类,不行那样还是每个viewController都要改;有没有让新项目改动极少的代码就可以实现的方法呢?答案是有的,只需要Category和黑科技Method Swizzling即可。

    首先建两个UIViewController的Category.
    第一个为UIViewController+CFYNavigationBarTransition.h

    // UIViewController CFYNavigationBarTransition
    @interface UIViewController (CFYNavigationBarTransition)
    /**
     设置导航栏是否隐藏
     
     @param hidden 隐藏
     @param animated 动画
     */
    - (void)cfy_setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated;
    
    @end
    

    第二个位UINavigationController+CFYNavigationBarTransition_Public.h

    @interface UIViewController (CFYNavigationBarTransition_Public)
    
    /**
     设置导航栏背景色
     
     @param color 背景色
     */
    - (void)cfy_setNavigationBarBackgroundColor:(UIColor *)color;
    
    /**
     设置背景图片
    
     @param image 背景图
     */
    - (void)cfy_setNavigationBarBackgroundImage:(UIImage *)image;
    
    /**
     设置导航栏透明度
     
     @param alpha 透明度
     */
    - (void)cfy_setNavigationBarAlpha:(CGFloat)alpha;
    
    /**
     bar背景色
     */
    @property (readonly) UIColor *cfy_navigationBarBackgroundColor;
    
    /**
     bar透明度
     */
    @property (readonly) CGFloat cfy_navigationBarAlpha;
    
    @end
    

    两个都是UIViewController的Category,以public结尾的文件中是对外提供公开的方法和属性,也就是用户可以使用的方法和属性,另个则是放私有方法和属性。
      两个category中方法和属性的实现都在UIViewController+CFYNavigationBarTransition.m中实现,实现逻辑加在了注释中

    @interface UIViewController ()
    
    /**
     cfy_navBarBgView,这个view就是核心,改变navigationBar颜色其实是改变cfy_navBarBgView的背景色
     */
    @property (nonatomic, strong) UIView *cfy_navBarBgView;
    
    /**
     用来判断view是否加载
     */
    @property (nonatomic, assign) BOOL cfy_viewAppeared;
    
    /**
     保存navigationBar颜色
     */
    @property (nonatomic, strong) UIColor *cfy_navigationBarBackgroundColor;
    
    /**
     保存navigationBar颜色透明度
     */
    @property (nonatomic, assign) CGFloat cfy_navigationBarAlpha;
    
    @end
    
    
    @implementation UIViewController (CFYNavigationBarTransition)
    /**
     在load中,swizzle四个方法viewDidLoad、viewWillLayoutSubviews、viewDidAppear:、viewDidDisappear:。
     */
    +(void)load {
        CFYSwizzleMethod(self, @selector(viewDidLoad), @selector(cfy_viewDidLoad));
        CFYSwizzleMethod(self, @selector(viewWillLayoutSubviews), @selector(cfy_viewWillLayoutSubviews));
        CFYSwizzleMethod(self, @selector(viewDidAppear:), @selector(cfy_viewDidAppear:));
        CFYSwizzleMethod(self, @selector(viewDidDisappear:), @selector(cfy_viewDidDisappear:));
    }
    
    /**
     在viewDidLoad中添加cfy_navBarBgView
     */
    - (void)cfy_viewDidLoad {
        [self cfy_viewDidLoad];
        // 如果存在navigationController则添加cfy_navBarBgView
        if (self.navigationController) {
            [self cfy_addNavBarBgView];
        }
    }
    
    - (void)cfy_viewDidAppear:(BOOL)animated {
        [self cfy_viewDidAppear:animated];
        self.cfy_viewAppeared = YES;
    }
    
    - (void)cfy_viewDidDisappear:(BOOL)animated {
        [self cfy_viewDidDisappear:YES];
        self.cfy_viewAppeared = NO;
    }
    
    
    /**
     在viewWillLayoutSubviews中对cfy_navBarBgView进行处理,使cfy_navBarBgView能在不同环境正确显示
     */
    - (void)cfy_viewWillLayoutSubviews {
        [self cfy_viewWillLayoutSubviews];
        // 当前viewController没navigationController,直接退出
        if (!self.navigationController) {
            return;
        }
        /**
         self.navigationController.navigationBar隐藏了,做一些处理。
         如果在navigationBar隐藏时,旋转屏幕,这时如果不处理后并return,而是走下面的代码,那么并不能正确的获取到cfy_navBarBgView的frame。
         所以在这里直接将cfy_navBarBgView的宽度设置成屏幕看度,其他不变保持cfy_navBarBgView在隐藏前的状态,这样在从竖屏切换到横屏显示时不会出现一些视觉上的bug
         
         */
        if (self.navigationController.navigationBar.hidden) {
            CGRect rect = self.cfy_navBarBgView.frame;
            self.cfy_navBarBgView.frame = CGRectMake(0, rect.origin.y, CFYScreenWidth, rect.size.height);
            return;
        }
        
        // 获取navigationBar的backgroundView
        UIView *backgroundView = [self.navigationController.navigationBar valueForKey:@"_backgroundView"];
        // 如果没有则return
        if (!backgroundView) {
            return;
        }
        
        // 获取navigationBar的backgroundView在self.view中的位置,这个位置也就是cfy_navBarBgView所在的位置。
        CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.view];
        
        // 出现rect.origin.x < 0,情况只有在页面刚push出来并且navigationBar隐藏的时候。
        // 这个时候讲rect.origin.y上移rect.size.height,使cfy_navBarBgView也隐藏
        // 目的是防止在navigationBar.hidden=NO时出现动画显示错误
        if (rect.origin.x < 0) {
            rect.origin.y = 0 - rect.size.height;
        }
        
        // cfy_navBarBgView的x固定0
        self.cfy_navBarBgView.frame = CGRectMake(0, rect.origin.y, rect.size.width, rect.size.height);
        
        // 设置当前view的clipsToBounds = NO,原因是,self.view.top可能是从navigationBar.bottom开始,如果clipsToBounds = YES,则cfy_navBarBgView无法显示
        self.view.clipsToBounds = NO;
        // 将cfy_navBarBgView移到self.view最顶端,防止被其他view遮盖
        [self.view bringSubviewToFront:self.cfy_navBarBgView];
    }
    
    #pragma mark - 公开方法 -
    /**
     设置导航栏背景色
     
     @param color 背景色
     */
    - (void)cfy_setNavigationBarBackgroundColor:(UIColor *)color {
        self.cfy_navigationBarBackgroundColor = color;
        if (self.navigationController) {
            self.cfy_navBarBgView.backgroundColor = color;
        }
    }
    
    /**
     设置背景图片
     
     @param image 背景图
     */
    - (void)cfy_setNavigationBarBackgroundImage:(UIImage *)image {
        // 后续版本加入
    }
    
    /**
     设置导航栏透明度
     
     @param alpha 透明度
     */
    - (void)cfy_setNavigationBarAlpha:(CGFloat)alpha {
        self.cfy_navigationBarAlpha = alpha;
        if (self.navigationController) {
            self.cfy_navBarBgView.alpha = alpha;
        }
    }
    
    #pragma mark - 私有方法 -
    /**
     设置导航栏是否隐藏
     
     @param hidden 隐藏
     @param animated 动画
     */
    - (void)cfy_setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated {
        if (self.navigationController) {
            // 这里只在cfy_navBarBgView隐藏时使用了动画,原因是cfy_navBarBgView显示时系统自动给加上了动画(这很神奇)
            if (hidden && self.cfy_viewAppeared && animated && !self.navigationController.navigationBar.hidden) {
                // 在cfy_navBarBgView隐藏,并且view已经Appeared,并且有动画,并且navigationBar不是已经隐藏了时就进行动画
                CGRect rect = self.cfy_navBarBgView.frame;
                [UIView animateWithDuration:0.2 animations:^{
                    // 动画时向上运动
                    self.cfy_navBarBgView.frame = CGRectMake(0, rect.origin.y - rect.size.height, rect.size.width, rect.size.height);
                } completion:^(BOOL finished) {
                    // 动画完成后cfy_navBarBgView隐藏
                    self.cfy_navBarBgView.hidden = hidden;
                }];
            } else {
                self.cfy_navBarBgView.hidden = hidden;
            }
        }
    }
    
    
    
    /**
     添加navigationBar背景view
     */
    - (void)cfy_addNavBarBgView {
        if (!self.isViewLoaded) {
            return;
        }
        if (!self.navigationController) {
            return;
        }
        if (!self.navigationController.navigationBar) {
            return;
        }
        
        // 获取NavigationBar的BackgroundView在当前view中的位置
        CGRect rect = [self cfy_getNavigationBarBackgroundViewRect];
        
        // 初始化
        UIView *navBarBgView = [[UIView alloc] initWithFrame:CGRectMake(0, rect.origin.y, rect.size.width, rect.size.height)];
        [self.view addSubview:navBarBgView];
        
        // 判断有没有设置颜色
        if (self.cfy_navigationBarBackgroundColor) {
            navBarBgView.backgroundColor = self.cfy_navigationBarBackgroundColor;
        } else {
            // 默认是白色
            navBarBgView.backgroundColor = [UIColor whiteColor];
            self.cfy_navigationBarBackgroundColor = [UIColor whiteColor];
        }
        // 设置透明度,默认为1
        navBarBgView.alpha = self.cfy_navigationBarAlpha;
        // 是否隐藏
        navBarBgView.hidden = self.navigationController.navigationBar.isHidden;
        // 保存
        [self setCfy_navBarBgView:navBarBgView];
    }
    
    
    /**
     获取navigationBar._backgroundView在self.view中的frame
    
     @return _backgroundView的frame
     */
    - (CGRect)cfy_getNavigationBarBackgroundViewRect {
        UIView *backgroundView = [self.navigationController.navigationBar valueForKey:@"_backgroundView"];
        if (!backgroundView) {
            return CGRectZero;
        }
        CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.view];
        return rect;
    }
    
    #pragma mark - getter/setter -
    -(UIView *)cfy_navBarBgView {
        UIView *navBarBgView = objc_getAssociatedObject(self, _cmd);
        
        if (nil == navBarBgView) {
            [self cfy_addNavBarBgView];
        }
        
        return navBarBgView;
    }
    
    - (void)setCfy_navBarBgView:(UIView *)navBarBgView {
        objc_setAssociatedObject(self, @selector(cfy_navBarBgView), navBarBgView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (BOOL)cfy_viewAppeared {
        return [objc_getAssociatedObject(self, _cmd) boolValue];
    }
    
    - (void)setCfy_viewAppeared:(BOOL)viewAppeared {
        objc_setAssociatedObject(self, @selector(cfy_viewAppeared), @(viewAppeared), OBJC_ASSOCIATION_ASSIGN);
    }
    
    - (UIColor *)cfy_navigationBarBackgroundColor {
        return objc_getAssociatedObject(self, _cmd);
    }
    
    - (void)setCfy_navigationBarBackgroundColor:(UIColor *)navigationBarBackgroundColor {
        objc_setAssociatedObject(self, @selector(cfy_navigationBarBackgroundColor), navigationBarBackgroundColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    -(CGFloat)cfy_navigationBarAlpha {
        NSNumber *alpha = objc_getAssociatedObject(self, _cmd);
        if (!alpha) {
            [self setCfy_navigationBarAlpha:1.];
            return 1.;
        }
        
        return [alpha floatValue];
    }
    
    - (void)setCfy_navigationBarAlpha:(CGFloat)navigationBarAlpha {
        objc_setAssociatedObject(self, @selector(cfy_navigationBarAlpha), @(navigationBarAlpha), OBJC_ASSOCIATION_ASSIGN);
    }
    @end
    

    OK,主要功能完成,上面代码中还有几个问题:

    • 问题1:在设置[navigationController setNavigationBarHidden:animated:]和[navigationController setNavigationBarHidden:]方法是应该对cfy_navBarBgView进行操作;
    • 问题2:没有设置NavigationBar为透明,不设置成透明,前面的工作都白做了。

    那么对navigationController也建一个Category,并swizzle需要的方法。代码如下:
    UIViewController+CFYNavigationBarTransition.m

    @interface UIViewController ()
    
    /**
     cfy_navBarBgView,这个view就是核心,改变navigationBar颜色其实是改变cfy_navBarBgView的背景色
     */
    @property (nonatomic, strong) UIView *cfy_navBarBgView;
    
    /**
     用来判断view是否加载
     */
    @property (nonatomic, assign) BOOL cfy_viewAppeared;
    
    /**
     保存navigationBar颜色
     */
    @property (nonatomic, strong) UIColor *cfy_navigationBarBackgroundColor;
    
    /**
     保存navigationBar颜色透明度
     */
    @property (nonatomic, assign) CGFloat cfy_navigationBarAlpha;
    
    @end
    
    
    @implementation UIViewController (CFYNavigationBarTransition)
    /**
     在load中,swizzle四个方法viewDidLoad、viewWillLayoutSubviews、viewDidAppear:、viewDidDisappear:。
     */
    +(void)load {
        CFYSwizzleMethod(self, @selector(viewDidLoad), @selector(cfy_viewDidLoad));
        CFYSwizzleMethod(self, @selector(viewWillLayoutSubviews), @selector(cfy_viewWillLayoutSubviews));
        CFYSwizzleMethod(self, @selector(viewDidAppear:), @selector(cfy_viewDidAppear:));
        CFYSwizzleMethod(self, @selector(viewDidDisappear:), @selector(cfy_viewDidDisappear:));
    }
    
    /**
     在viewDidLoad中添加cfy_navBarBgView
     */
    - (void)cfy_viewDidLoad {
        [self cfy_viewDidLoad];
        // 如果存在navigationController则添加cfy_navBarBgView
        if (self.navigationController) {
            [self cfy_addNavBarBgView];
        }
    }
    
    - (void)cfy_viewDidAppear:(BOOL)animated {
        [self cfy_viewDidAppear:animated];
        self.cfy_viewAppeared = YES;
    }
    
    - (void)cfy_viewDidDisappear:(BOOL)animated {
        [self cfy_viewDidDisappear:YES];
        self.cfy_viewAppeared = NO;
    }
    
    
    /**
     在viewWillLayoutSubviews中对cfy_navBarBgView进行处理,使cfy_navBarBgView能在不同环境正确显示
     */
    - (void)cfy_viewWillLayoutSubviews {
        [self cfy_viewWillLayoutSubviews];
        // 当前viewController没navigationController,直接退出
        if (!self.navigationController) {
            return;
        }
        /**
         self.navigationController.navigationBar隐藏了,做一些处理。
         如果在navigationBar隐藏时,旋转屏幕,这时如果不处理后并return,而是走下面的代码,那么并不能正确的获取到cfy_navBarBgView的frame。
         所以在这里直接将cfy_navBarBgView的宽度设置成屏幕看度,其他不变保持cfy_navBarBgView在隐藏前的状态,这样在从竖屏切换到横屏显示时不会出现一些视觉上的bug
         
         */
        if (self.navigationController.navigationBar.hidden) {
            CGRect rect = self.cfy_navBarBgView.frame;
            self.cfy_navBarBgView.frame = CGRectMake(0, rect.origin.y, CFYScreenWidth, rect.size.height);
            return;
        }
        
        // 获取navigationBar的backgroundView
        UIView *backgroundView = [self.navigationController.navigationBar valueForKey:@"_backgroundView"];
        // 如果没有则return
        if (!backgroundView) {
            return;
        }
        
        // 获取navigationBar的backgroundView在self.view中的位置,这个位置也就是cfy_navBarBgView所在的位置。
        CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.view];
        
        // 出现rect.origin.x < 0,情况只有在页面刚push出来并且navigationBar隐藏的时候。
        // 这个时候讲rect.origin.y上移rect.size.height,使cfy_navBarBgView也隐藏
        // 目的是防止在navigationBar.hidden=NO时出现动画显示错误
        if (rect.origin.x < 0) {
            rect.origin.y = 0 - rect.size.height;
        }
        
        // cfy_navBarBgView的x固定0
        self.cfy_navBarBgView.frame = CGRectMake(0, rect.origin.y, rect.size.width, rect.size.height);
        
        // 设置当前view的clipsToBounds = NO,原因是,self.view.top可能是从navigationBar.bottom开始,如果clipsToBounds = YES,则cfy_navBarBgView无法显示
        self.view.clipsToBounds = NO;
        // 将cfy_navBarBgView移到self.view最顶端,防止被其他view遮盖
        [self.view bringSubviewToFront:self.cfy_navBarBgView];
    }
    
    #pragma mark - 公开方法 -
    /**
     设置导航栏背景色
     
     @param color 背景色
     */
    - (void)cfy_setNavigationBarBackgroundColor:(UIColor *)color {
        self.cfy_navigationBarBackgroundColor = color;
        if (self.navigationController) {
            self.cfy_navBarBgView.backgroundColor = color;
        }
    }
    
    /**
     设置背景图片
     
     @param image 背景图
     */
    - (void)cfy_setNavigationBarBackgroundImage:(UIImage *)image {
        // 后续版本加入
    }
    
    /**
     设置导航栏透明度
     
     @param alpha 透明度
     */
    - (void)cfy_setNavigationBarAlpha:(CGFloat)alpha {
        self.cfy_navigationBarAlpha = alpha;
        if (self.navigationController) {
            self.cfy_navBarBgView.alpha = alpha;
        }
    }
    
    #pragma mark - 私有方法 -
    /**
     设置导航栏是否隐藏
     
     @param hidden 隐藏
     @param animated 动画
     */
    - (void)cfy_setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated {
        if (self.navigationController) {
            // 这里只在cfy_navBarBgView隐藏时使用了动画,原因是cfy_navBarBgView显示时系统自动给加上了动画(这很神奇)
            if (hidden && self.cfy_viewAppeared && animated && !self.navigationController.navigationBar.hidden) {
                // 在cfy_navBarBgView隐藏,并且view已经Appeared,并且有动画,并且navigationBar不是已经隐藏了时就进行动画
                CGRect rect = self.cfy_navBarBgView.frame;
                [UIView animateWithDuration:0.2 animations:^{
                    // 动画时向上运动
                    self.cfy_navBarBgView.frame = CGRectMake(0, rect.origin.y - rect.size.height, rect.size.width, rect.size.height);
                } completion:^(BOOL finished) {
                    // 动画完成后cfy_navBarBgView隐藏
                    self.cfy_navBarBgView.hidden = hidden;
                }];
            } else {
                self.cfy_navBarBgView.hidden = hidden;
            }
        }
    }
    
    
    
    /**
     添加navigationBar背景view
     */
    - (void)cfy_addNavBarBgView {
        if (!self.isViewLoaded) {
            return;
        }
        if (!self.navigationController) {
            return;
        }
        if (!self.navigationController.navigationBar) {
            return;
        }
        
        // 获取NavigationBar的BackgroundView在当前view中的位置
        CGRect rect = [self cfy_getNavigationBarBackgroundViewRect];
        
        // 初始化
        UIView *navBarBgView = [[UIView alloc] initWithFrame:CGRectMake(0, rect.origin.y, rect.size.width, rect.size.height)];
        [self.view addSubview:navBarBgView];
        
        // 判断有没有设置颜色
        if (self.cfy_navigationBarBackgroundColor) {
            navBarBgView.backgroundColor = self.cfy_navigationBarBackgroundColor;
        } else {
            // 默认是白色
            navBarBgView.backgroundColor = [UIColor whiteColor];
            self.cfy_navigationBarBackgroundColor = [UIColor whiteColor];
        }
        // 设置透明度,默认为1
        navBarBgView.alpha = self.cfy_navigationBarAlpha;
        // 是否隐藏
        navBarBgView.hidden = self.navigationController.navigationBar.isHidden;
        // 保存
        [self setCfy_navBarBgView:navBarBgView];
    }
    
    
    /**
     获取navigationBar._backgroundView在self.view中的frame
    
     @return _backgroundView的frame
     */
    - (CGRect)cfy_getNavigationBarBackgroundViewRect {
        UIView *backgroundView = [self.navigationController.navigationBar valueForKey:@"_backgroundView"];
        if (!backgroundView) {
            return CGRectZero;
        }
        CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.view];
        return rect;
    }
    
    #pragma mark - getter/setter -
    -(UIView *)cfy_navBarBgView {
        UIView *navBarBgView = objc_getAssociatedObject(self, _cmd);
        
        if (nil == navBarBgView) {
            [self cfy_addNavBarBgView];
        }
        
        return navBarBgView;
    }
    
    - (void)setCfy_navBarBgView:(UIView *)navBarBgView {
        objc_setAssociatedObject(self, @selector(cfy_navBarBgView), navBarBgView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (BOOL)cfy_viewAppeared {
        return [objc_getAssociatedObject(self, _cmd) boolValue];
    }
    
    - (void)setCfy_viewAppeared:(BOOL)viewAppeared {
        objc_setAssociatedObject(self, @selector(cfy_viewAppeared), @(viewAppeared), OBJC_ASSOCIATION_ASSIGN);
    }
    
    - (UIColor *)cfy_navigationBarBackgroundColor {
        return objc_getAssociatedObject(self, _cmd);
    }
    
    - (void)setCfy_navigationBarBackgroundColor:(UIColor *)navigationBarBackgroundColor {
        objc_setAssociatedObject(self, @selector(cfy_navigationBarBackgroundColor), navigationBarBackgroundColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    -(CGFloat)cfy_navigationBarAlpha {
        NSNumber *alpha = objc_getAssociatedObject(self, _cmd);
        if (!alpha) {
            [self setCfy_navigationBarAlpha:1.];
            return 1.;
        }
        
        return [alpha floatValue];
    }
    
    - (void)setCfy_navigationBarAlpha:(CGFloat)navigationBarAlpha {
        objc_setAssociatedObject(self, @selector(cfy_navigationBarAlpha), @(navigationBarAlpha), OBJC_ASSOCIATION_ASSIGN);
    }
    @end
    

    至此所有的代码完工。

    • 改变navigationBar的颜色,调用[viewController cfy_setNavigationBarBackgroundColor:bgColor]方法。
    • 改变navigationBar的透明度,调用[viewController cfy_setNavigationBarAlpha:alpha]方法.
    • 隐藏则直接调用UINavigationController中设置NavigationBar隐藏的方法
      注意事项:不要设置NavigationBar的translucent为NO,原因是设置了translucent=NO,NavigationBar就不能透明了。

    四、成果展示

    竖屏效果竖屏效果
    横屏效果横屏效果

    五、代码地址

    GitHub: CFYNavigationBarTransition
    Cocoapods:pod 'CFYNavigationBarTransition'

    相关文章

      网友评论

      • 丶狂舞:被页面导航栏的隐藏和显示时切换的问题困扰已久,今天终于解决了,感谢!!!
        CaffreySun:@丶狂舞 :relaxed:很高兴能帮助到你,有问题可以在这里或者github交流
      • 小强的强_:最近发现一个问题:
        用这个库,跟MJRefresh控件一起用,做了一个导航栏从透明渐变为黑色的效果。但是,偶尔会出现状态栏透明之后,不随着导航栏颜色改变,一直保持透明。这个是跟MJRefresh有啥冲突吗?
        小强的强_:OK,已经在github上提交了isuue。
        CaffreySun:@小强的强_ 可以在github上提issu
        CaffreySun:@小强的强_ 最近我会看看这个问题,如果找到解决方法,我会回复你
      • louisly:想请问,两个页面一个黑一个白的navbar title也是一个黑一个白,这个title的颜色怎么渐变?
      • iosder:用了大神你的库,调用系统自带相机,会有2个CFYNavigationBar 遮挡住相机上部。不知道什么原因,求解答
        iosder:@LieRen 我调用这开关方法没用,不知道我调用的问题还是代码问题,所以就没用这个三方了
        LieRen:@CaffreySun (调用系统自带相机,会有2个CFYNavigationBar 遮挡住相机上部。)这个问题能不能在源码中做一下处理,因为项目中用到的话还要单独对系统相机进行开关的话,closeCFYNavigationBarFunction 起的作用就不全了,应该让closeCFYNavigationBarFunction作用到相机imageViewcontroller等所有navigationController类中
        CaffreySun:库带有一个开关,开关作用在NavigationController上,调用系统的相机会有一个NavigationController,需要手动关闭相机NavigationController的开关
      • songu:[UINavigationBar appearance] 跟此库会有冲突吗?如何兼容?
        CaffreySun:不好意思,最近有点忙,没有注意留言。你指的冲突有哪些呢。当前版本确实没有适配[UINavigationBar appearance],不过这两天我会发布新版本上去,适配[UINavigationBar appearance]的barTintColor、shadowImage。
      • 梵高的老巫婆:大神 就直接说iOS 10之后怎么设置NavigationBar的背景颜色吧
        CaffreySun:暂时没有发现完美的原生的方案。使用文章底部的库来实现吧。

      本文标题:iOS NavigationBar颜色、透明度、隐藏设置探究

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