iOS透明导航栏的平滑过渡(进阶版) - Go语言中文社区

iOS透明导航栏的平滑过渡(进阶版)


如我在传送门:iOS导航栏切换界面时隐藏和显示中所说,现在很多App的个人中心模块都是不保留导航栏的,会直接使导航栏透明,比如做的很好的QQ个人信息界面:

20170322191021805.png

为什么说QQ做的很好呢?既然有透明的导航栏也有不透明的导航栏,那一定会在界面切换之间存在一个过渡的过程,而这个过程,QQ做的特别好,在从透明导航栏界面返回到不透明导航栏界面时,导航栏的透明度是一个渐进的过渡效果,甚至会有一种毛玻璃的效果,感兴趣的可以打开手机QQ到个人界面看一看,效果很赞。

而很多App的做法其实比较粗糙,类似于我在传送门:iOS导航栏切换界面时隐藏和显示中的做法,需要导航栏透明时,直接将导航栏隐藏起来。直接隐藏起来的意思是,整个导航栏就用不了了,也就是说,标题、返回按钮等都需要自己去做,这是一个比较麻烦的地方,此外,在有无导航栏的界面间切换时,过程是比较生硬的,导航栏不是渐变出现的。如果说这些都可以接受,那最大的一个问题,也是我在那篇文章里提到的,如果正好处于用UITabbarConatroller切换界面,那么导航栏会有一个往上缩回的快速动画,这其实就很不美观了,当然我们可以通过将隐藏导航栏的动画去掉来达到对Tabbar切换友好的效果:

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

但是这样一来你在UINavigationController体系下切换界面时由于没有了动画,这边的效果又会变得很差。这两个矛盾没有想到可以调和的手段,除非在业务上就不显示Tabbar了,但始终不是长久之计。

同时,我们虽然说QQ做的很好,但也依然有一些不足,多把玩一下导航栏过渡的过程就会发现,如果准备从透明导航栏返回时又决定不反回了,还是停留在导航栏透明的界面,这时候导航栏虽然会回到透明,但会有一个导航栏闪现一下的小瑕疵。

现在问题已经讲完了,基于这些问题,我们自己来尝试实现一种更好的平滑过渡效果,不自定义导航栏,直接利用系统原生的导航栏,使用Category和Runtime的技术,达到这个效果:

20170322193055722.gif

代码可以在示例工程下载(觉得有帮助的小伙伴请不吝加Star~):https://github.com/Cloudox/SmoothNavDemo

实现过程

其实我们的目的总结起来有三个:

1、不去自定义导航栏,就用系统原生的,标题、返回按钮啥的都方便加,这也就是说不隐藏导航栏,而是要单独让导航栏背景透明; 

2、在导航栏透明与否的界面间切换时透明度有渐变效果; 

3、在UINavigationController体系和UITabarController体系下切换界面都很完美。

对于第三个目的,我们之前在UITabarController下切换时会有导航栏隐藏的小动画,但如果我们满足了第一个目的,那就不存在隐藏导航栏了,所以第三个问题也就不会存在了。

我们先来看第一个目的。

设置导航栏背景透明度

导航栏上应该是有很多view的,我们要做的是只让背景透明,而保留标题、返回按钮。iOS没有直接给我们提供对于导航栏背景view的访问途径,那么我们只能自己来找了。

首先我们遍历打印出UINavigationBar的所有子视图,是所有,包括子视图的一层层子视图,来看看到底导航栏都包含了哪些东西:

20170320200018245.png

上面这张图就是导航栏UINavigationBar所包含的所有子view了,序号和缩进表示了其层级归属关系,打印的方法可以看这篇文章:传送门:iOS遍历打印所有子视图

从这些子view的类名能够大概猜出他们都是导航栏上的什么,让我们大胆猜测一下,_UIBarBackground 是背景视图,下属的 UIImageView 是背景图片,_UINavigationBarBackIndicatorView 是返回箭头,UINavigationItemView 是添加的一些导航栏按钮,包括返回按钮,因为我没有给导航栏添加任何其他按钮,所以这里一定是返回按钮,下属的 UILabel 就是 “返回” 两个字了。

根据上面得到的信息,我们就尝试将_UIBarBackground、UIImageView、UIVisualEffectView的 alpha 值设为 1 或者 0 来改变导航栏背景的透明度。

我们可以给 UINavigationController 创建一个类别,来给这个类添加一个方法,用于设置导航栏的透明度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// UIViewController+Cloudox.m
 
- (void)setNeedsNavigationBackground:(CGFloat)alpha {
    // 导航栏背景透明度设置
    UIView *barBackgroundView = [[self.navigationBar subviews] objectAtIndex:0];// _UIBarBackground
    UIImageView *backgroundImageView = [[barBackgroundView subviews] objectAtIndex:0];// UIImageView
    if (self.navigationBar.isTranslucent) {
        if (backgroundImageView != nil && backgroundImageView.image != nil) {
            barBackgroundView.alpha = alpha;
        else {
            UIView *backgroundEffectView = [[barBackgroundView subviews] objectAtIndex:1];// UIVisualEffectView
            if (backgroundEffectView != nil) {
                backgroundEffectView.alpha = alpha;
            }
        }
    else {
        barBackgroundView.alpha = alpha;
     版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/JXT141014_150214/article/details/69666753
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 18:43:03
  • 阅读 ( 1457 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢