iOS导航栏

作者: iOneWay | 来源:发表于2016-05-21 16:37 被阅读2014次

    iOS7之后UI发生大变化。apple鼓励开发者进行全屏设计,这些并在UI的一些特性上也有所表现。

    1.屏幕坐标起始点的变化
    新建一个UIViewController并作为项目的RootController,在其View顶部添加一个UILabel,frame=(0,0,200,20)如图:

    bar01.png

    可以发现label与导航栏发生了重叠,由此可以推知:

    iOS7后,坐标(0, 0)从整个屏幕的左上顶点开始计算。
    

    当我们在该UIViewController外套一个UINavigationController后显示如图:


    bar02.png

    整个label被UINavigationBar覆盖了。

    利用检测任意view的subviews的关系树一文中提供的工具方法打印keyWIndow的subViews树:如图

    bar03.png

    由上图可以知晓:

    UINavigationBar的高度依旧是44px,
     其子View: UINavigationBarBackground高度为64px,origin.y=-20,
    所以UINavigationBarBackground充当了状态栏和导航栏的背景。这也解释了通过修改UINavigationBar背景来改变导航栏背景的原理。
    

    我们为UINavigationBar添加背景图片:如图

    bar04.png

    此时打印视图树,如图:

    bar05.png

    label视图出现在了导航栏下方,该效果由UIViewController的一个属性决定的:extendedLayoutIncludesOpaqueBars,这个属性指定了当Bar使用了不透明图片时,视图是否延伸至Bar所在区域,默认值时NO。如果把这个属性设置为YES,那么视图将会延伸至导航栏区域,即使我们把导航栏设置成了自定义背景。

    1, 通过修改UINavigationBar的背景可以来修改状态栏背景
    2, 当UIViewController. extendedLayoutIncludesOpaqueBars = NO 时,UINavigationBar添加背景图片后,UIViewController的视图的原点坐标为(0, 64), 下移了64px,并且高度缩减了64px。
    

    通过设置UIViewController的属性:edgesForExtendedLayout来使label出现在导航栏下方:

    self.edgesForExtendedLayout = UIExtendedEdgeNone;
    

    如图:视图不会再延伸到导航栏后面了

    bar06.png bar07.png

    可以发现界面的变化,由此得出:

    与为UINavigationBar添加背景图片效果相同
    
    当视图中存在UIScrollView时

    1,存在唯一一个UIScrollView或者其子类时:<注意唯一一个>

    • ScrollView为添加的第一个子视图
      代码:
    override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = UIColor.whiteColor()
    
             /*****添加顶部UITableView*****/
            let table = UITableView.init(frame: self.view.bounds, style: .Plain);
            table.delegate = self;
            table.dataSource = self;
            self.view .addSubview(table)
            
            self.automaticallyAdjustsScrollViewInsets = true;
      
            /*****添加顶部UILabel*****/
            let label = UILabel.init(frame: CGRectMake(0, 0, 200, 20))
            label.text = "I am a label";
            self.view .addSubview(label)
        }
    

    效果和视图树如图:

    bar08.png
    bar09.png

    分析:
    以上代码self.automaticallyAdjustsScrollViewInsets = true;,其中属性automaticallyAdjustsScrollViewInsets默认为true; 当其值为true时,如果视图里面存在唯一一个UIScrollView或其子类View,那么它会自动设置相应的内边距,但是不会重置scrollView的frame,这样可以让scroll占据整个视图,又不会让导航栏遮盖。

    • ScrollView不是添加的第一个子视图或者不止一个ScrollView
      代码:
     override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = UIColor.whiteColor()
            
            /*****添加顶部UILabel*****/
            let label = UILabel.init(frame: CGRectMake(0, 0, 200, 20))
            label.text = "I am a label";
            self.view .addSubview(label)
            
             /*****添加顶部Table*****/
            let table = UITableView.init(frame: self.view.bounds, style: .Plain);
            table.delegate = self;
            table.dataSource = self;
            self.view .addSubview(table)
            
            self.automaticallyAdjustsScrollViewInsets = true;
        }
    

    本次是先添加label然后添加ScrollView,其效果和子视图如图:

    bar11.png bar10.png

    分析:代码self.automaticallyAdjustsScrollViewInsets = true;失效了。

    此时我门可以使用属性:self.edgesForExtendedLayout = UIExtendedEdgeNone;,然后将ScrollView的高相应的缩减64px,来达到目的。

    总结

    iOS7之后apple鼓励开发者使用全屏布局,这样导致了视图的原点(0,0)为屏幕左上顶点,而不再是状态栏左下位置开始。

    UIViewController的属性:

    extendedLayoutIncludesOpaqueBars, 默认为false,
    说明:这个属性指定了当Bar使用了不透明图片时,视图是否延伸至Bar所在区域,默认值时false。
    所以我们如果自定义了导航栏的背景图片,那么视图会从导航栏以下开始,不会延伸到导航栏区域。
    如果把这个属性设置为true,那么视图将会延伸至导航栏区域,即使我们把导航栏设置成了自定义背景

    edgesForExtendedLayout, 默认为UIExtendedEdgeNone,
    说明: 这个属性指定边缘要延伸的方向。
    因为iOS7鼓励全屏布局,它的默认值很自然地是UIRectEdgeAll,四周边缘均延伸,就是说,如果即使视图中上有navigationBar,下有tabBar,那么视图仍会延伸覆盖到四周的区域。

    automaticallyAdjustsScrollViewInsets, 默认为true
    当设置为YES时(默认YES),如果视图里面存在唯一一个且为第一个加入视图的UIScrollView或其子类View,那么它会自动设置相应的内边距,这样可以让scroll占据整个视图,又不会让导航栏遮盖。若ScrollView不止一个或者不是第一个加入子视图则该属性将失效。

    导航栏图片背景

    添加背景图片

     self.navigationController?.navigationBar .setBackgroundImage(UIImage.init(imageLiteral: "barbar66.png"), forBarPosition: UIBarPosition.Top, barMetrics: UIBarMetrics.Default)
    

    1,作为导航背景的图片:该图片是一个@2x图片:160*88

    barbar88@2x.png

    效果如图:

    bar12.png

    2,将图片换成barbar66@2x.png:160*66
    效果如图:

    bar13.png

    3,将图片换成barbar100@2x.png:182*100
    效果如图:

    bar14.png

    4,将图片换成barbar100@2x.png:182*128
    效果如图:

    bar15.png

    5,将图片换成barbar228@2x.png:415*228
    效果如图:

    bar16.png

    有以上结果可见:
    假设图片高度为h,

    1. 当h<88 或者 88<h<128时,纵向横向平铺,覆盖导航栏
    2. 当h=88时,横向平铺,不覆盖导航栏
    3. 当h=128时,横向平铺,覆盖导航栏
    4. 当h>128时,纵向截取,横向平铺,覆盖导航栏

    得到以上结论的前提是:所有图片是@2x图。关于一倍图,无论何种情况都是横向平铺纵向拉伸。

    有关参数:BarPosition和barMetrics的确切作用目前还不十分清楚,等弄清楚了后续补充。

    附上UINavigationBar的扩展,内涵:bar去下边线,bar透明,bar恢复默认状态等。见地址:http://pan.baidu.com/s/1i4UqdFJ

    以上内容如有不足或错误欢迎指正留言。

    相关文章

      网友评论

      • 西叶lv:我打印了一下,导航栏设置背景图片后,高度不减64,还是原来高度,子视图的坐标原点确实是(0.64)
      • 建筑工匠:嗯,大神膜拜了,
        建筑工匠:@iOneWay 你谦虚了,这么细致,将来必成大牛
        iOneWay:@木子歌 我一菜鸟
      • Tieria:写的很详细
      • xxttw:很棒 分析的到位

      本文标题:iOS导航栏

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