美文网首页
迷之“导航栏”

迷之“导航栏”

作者: myzhing | 来源:发表于2016-12-21 22:15 被阅读0次

    对于初学者来说,IOS中的导航栏确实是一个让人困惑的知识点,我开始也是在项目预定的框架
    下去设置导航栏的一些属性,直到我负责的模块在IOS10中出现了导航栏的bug的时候才不得不
    去好好消化这一块,去理解系统在导航切换时的一些特效,去调研市面上常用APP对于导航栏
    的一些处理,这里我就来分解一下导航栏的奥秘。

    导航栏基础

    我们见到的导航栏大致由两部分组成,分别是navigationBar和navigationItem。

    • navigationBar

    豪无疑问navigationBar是属于navigationController的一部分,其不属于单个的UIViewController
    我们在同一个navigationController中push或者pop的时候,看到的Bar其实都是同一个,也就是
    说,在一个ViewController中修改了Bar在其它的ViewController中也是可见的。

    在考虑设置导航栏的时候,我们通常也是一起设置了App的状态栏(也就是电池条),IOS有两个常用的
    状态栏(statusBarStyle)属性,分别是:

    // Dark content, for use on light backgrounds
    UIStatusBarStyleDefault         = 0,
    // Light content, for use on dark backgrounds
    UIStatusBarStyleLightContent     NS_ENUM_AVAILABLE_IOS(7_0) = 1,
    

    导航栏始终处于状态栏的下方,我们可以看到几乎所有的App导航栏和状态栏的颜色
    都相同,这样的效果无法通过设置导航栏的backgroundColor得到,因为导航栏y坐标为20,
    状态栏,设置了导航栏的背景色不会影响到状态栏。但是神奇的是,导航栏上面还有一层
    View是navigationBarBackground(设置barTintColor将改变此背景色),其y坐标为-20,刚好把状态栏覆盖,所以我们使用setBackgroundImage就可以保证导航栏与状态栏同色,如下:

    UIImage *colorImage = [UIImage imageWithColor:[UIColor clearColor] size:CGSizeMake(1, 1)];
    [navc.navigationBar setBackgroundImage:colorImage forBarMetrics:UIBarMetricsDefault];
    [navc.navigationBar setShadowImage:colorImage];
    
    • navigationItem

    我们强调了navigationBar是属于navigationController的一部分,那么navigationItem
    却是属于UIViewCOntroller的一部分,这一点在刚开始很容易造成困惑,这些个Item明明
    就在Bar上,为什么偏偏属于ViewController,但是事实就是这样。navigationItem由三部分
    组成,分别是:

    1. titleView

    这又是一个让我们疑惑的属性,按照常理我们认为这是一个UILabel,通过设置navigationItem.
    titleView就是可以搞定title的一切属性,但是事实是我们想错了,这个属性默认为空。所以
    当我们要单独考虑一个viewController的title的时候,就需要为其设置一个UILabel作为
    titleView了,如下所示:

    - (void)setTitle:(NSString *)title titleColor:(UIColor *)color{
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 44)];
    titleLabel.text     = title;
    titleLabel.font     = [UIFont boldSystemFontOfSize:20.f];
    titleLabel.textAlignment  = NSTextAlignmentCenter;
    titleLabel.textColor    = color;
    self.navigationItem.titleView = titleLabel;
    }
    
    1. leftNavigationItem

    同上,其默认也为空(虽然系统会默认生成“返回”,但这个属性值依然为空)。所以我们一般
    会设置可控的leftNavigationItem,如下:

    - (void)setNavBarCustomBackButton:(NSString *)title target:(id)target action:(SEL)action {
    UIImage *image = [UIImage imageSVGNamed:@"icon_arrow_back_white" size:CGSizeMake(20, 20) cache:YES];
    
    UIButton *buttonItem = [UIButton buttonWithType:UIButtonTypeSystem];
    buttonItem.tag = 1002;
    buttonItem.titleLabel.font = [UIFont systemFontOfSize:16.0];
    buttonItem.imageEdgeInsets = UIEdgeInsetsMake(0, -16, 0, 0);
    buttonItem.titleEdgeInsets = UIEdgeInsetsMake(0, -19, 0, 0);
    [buttonItem setImage:image forState:UIControlStateNormal];
    [buttonItem setTitle:title forState:UIControlStateNormal];
    [buttonItem setTitleColor:RGB(45, 45, 45) forState:UIControlStateNormal];
    [buttonItem addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    [buttonItem sizeToFit];
    buttonItem.frame = CGRectMake(0, 0, buttonItem.frame.size.width, 40);
    
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:buttonItem];
    }
    
    1. rightNavigationItem

    其设置与leftNavigationItem一样,这里不啰嗦了。

    对于navigationItem的三个属性来说,其贯穿与整个App的开发过程中,我们为了代码的整洁性,
    一般不会在viewController中直接设置,而已通过category来使用。

    导航栏切换

    iOS10中navigationController的push和pop,前后两个viewController如果导航栏颜色(或者透明度)不一致,
    就会出现导航栏的切换动画,处理这种情况时应该特别小心,如果处理不当就会造成bug或者
    App体验上的损失。

    系统默认在导航栏切换的时候会有动画和毛玻璃效果,其实这个动画就是前后Controller的
    导航栏颜色的渐变动画,而且title也会随着动画产生“隐去”和“隐现”的效果,这种效果在
    一般情况下没有问题,而且看起来还很不错,但是下列两种情况下你应该单独考虑。

    • 一侧透明一侧不透明

    这种情况下就会产生奇怪的效果,一侧根本看不见导航栏,而系统给我们的是一个渐变的动画,
    然而这个动画仿佛在iOS10上有bug,会发生跳转闪烁的情况(在viewWillAppear中设置导航栏
    背景Image的效果会推迟显示)。如果我们可以接受这个动画,但是绝不能接受这个闪烁发生,
    可以尝试着修复这个bug;但是一些情况下我们并不期望这个动画产生,做法很简单把透明一侧
    的导航栏直接隐藏掉,这样前后viewController的导航栏渐进动画就会消失,很多blog上面
    说的就是这种方法。

    如果在透明一侧的导航栏的透明度是随着scrollView的contentOffset来变化的,那么隐藏导航栏这种
    解决办法就会失效,因为我们不能鲁莽地去隐藏掉一个透明度不为0的导航栏。这种情况下是
    逼着我们去实现自定义的转场动画,或者修复ios10上的bug,这两种解决办法都不会太简单,
    我会在接下来的文章中讲解。

    • 两侧主题相差巨大

    如果两侧导航栏的主题风格相差巨大,也就是说前后两个viewController根本不像是同一个
    navigationController中的子congtoller,那么系统中的渐变动画就会显得很不协调,想想
    在渐变动画中出现一个其它不相干的颜色是多么的抓狂。这里的解决办法也有两种,一种原理很简单
    ,就是在一侧放弃使用系统的导航栏,而伪造一个假的导航栏,这样就不会产生渐变动画。另一种
    方法还是自己实现转场动画,又回到了这个问题。

    市面上一些大的App,在处理上面两种情况的时候都放弃了系统的渐变动画,而是采用一种泾渭分明的
    转场方式,比如说今日头条、支付宝等,具体是使用伪导航栏还是自己实现的转场动画就不得而知了。
    特别说明:以上情况可能不适用于ios10之前,小心调试吧。

    Appearance主题

    上面已经讨论过,为navigationBar上面的item设置属性往往会造成困扰,我们有时候无法直接
    改变这些item的属性,所以需要设置自定义item。Appearance主题是为了设置整个App的默认属性,
    特别是对于UINavigation有用,能够设置App导航栏的色彩基调。如下:

    [[UINavigationBar appearance] setTintColor:RGB(0x51, 0x4e, 0x4e)];
    [[UINavigationBar appearance] setBarTintColor:RGB(0, 191, 143)];
    [[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont systemFontOfSize:15], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, nil]];
    [[UIBarButtonItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                                  [UIFont systemFontOfSize:15.0], NSFontAttributeName,
                                                                  RGB(0x51, 0x4e, 0x4e), NSForegroundColorAttributeName,
                                                                  nil]
                                                        forState:UIControlStateNormal];
    [[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageSVGNamed:@"icon_arrow_back_white" size:CGSizeMake(20, 20) cache:YES]];
    [[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageSVGNamed:@"icon_arrow_back_white" size:CGSizeMake(20, 20) cache:YES]];
    
    

    上述代码最好在App启动的时候就设置好,作为导航栏的默认设置,而且在项目的进行过程中不要轻易地再去更改。
    如果确实有需求更改navigationBar上的属性,记得在viewWillAppear或者viewWillDisappear中修改
    回去,或者直接使用自定义的item。

    相关文章

      网友评论

          本文标题:迷之“导航栏”

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