美文网首页iOS-Android-私房菜导航栏
iOS-与导航栏下控件的frame相关的edgesForExte

iOS-与导航栏下控件的frame相关的edgesForExte

作者: weyan | 来源:发表于2018-03-13 13:29 被阅读780次

    在引入了导航控制器UINavigationController和分栏控制器UITabBarController之后,我们在设置控件的frame的时候就需要注意避开导航栏UINavigationBar 44+电源栏UIStatusBar 20的高度,和底部分栏UITabBar 44的高度。底部分栏并没有太多需要处理的,我们只需要在计算高度的时候避开这44就可以了。而导航栏因为包含透明/半透明、第一个控件是否是UIScrollView或其子类等造成frame.origin.y的起点不同。我们现在来分析一下。

    1.edgesForExtendedLayout:UIRectEdge 扩展布局的边缘
      在iOS7以后 UIViewController 开始使用全屏布局,而且是默认的属性。通常涉及到布局,就离不开这个属性 edgesForExtendedLayout,它是一个类型为UIExtendedEdge的属性,指定UIViewController上的根视图self.view边缘要延伸的方向。由于iOS7鼓励全屏布局,所以它的默认值是UIRectEdgeAll,四周边缘均延伸,就是说,如果即使视图中上有UINavigationBar,下有UITabBar,那么视图仍会延伸覆盖到四周的区域。
    (1)UIRectEdgeAll(Defalut)


    image.png

    这里放置了一个frame为(0, 0, 100, 100)的view,backgroundColor设置为redColor,就是这个样子。也就是说,此时的self.view是从屏幕顶到屏幕底的。此时我们计算控件frame的y的时候,如果想把控件在导航栏底部开始,那么y就是64。
    (2)UIRectEdgeNone
    因此,我们为了不让我们的控件UIView延伸到UINavigationBar下面,我们可以将该属性设置为UIRectEdgeNone。代码如下:

    [self setEdgesForExtendedLayout:UIRectEdgeNone];
    

    ps:鉴于之前代码OC与Swift都有,可能带来的阅读不习惯,以后贴代码尽量使用OC,Swift独有的那就没办法了。


    image.png

    很清晰的可以看出来在设置为UIRectEdgeNone之后,self.view的是从导航栏底部到底部分栏顶部的。此时我们计算控件frame的y的时候,如果想把控件在导航栏底部开始,那么y就是0。

    (3)UIRectEdge

    typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
     2 
     3     UIRectEdgeNone   = 0,
     4 
     5     UIRectEdgeTop    = 1 << 0,
     6 
     7     UIRectEdgeLeft   = 1 << 1,
     8 
     9     UIRectEdgeBottom = 1 << 2,
    10 
    11     UIRectEdgeRight  = 1 << 3,
    12 
    13     UIRectEdgeAll    = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight  
    14 
    15 } NS_ENUM_AVAILABLE_IOS(7_0);
    

    很明显,UIRectEdge是个枚举类型。我们已经分析完了UIRectEdgeNone和UIRectEdgeAll,那么对UIRectEdgeTop和UIRectEdgeBottom也应该有所了解了。UIRectEdgeLeft/UIRectEdgeRight也不难猜测,就是对左右的扩展。目前没有遇到过左右两边系统控件可能覆盖掉自定义控件的情况,但遇到了我想大家也应该心里有数了吧。

    2.translucent:Bool 半透明的
    这个是self.navigationController.navigationBar的属性,设置导航条UINavigationBar是否半透明。默认是YES,也就是半透明,看起来比较高大上,与图1效果相同。
    当设置为不透明NO的时候,就涉及到下面第三条属性了,不过在第三条默认的情况下,则被下压,与图2效果相同。

    [self.navigationController.navigationBar setTranslucent:NO];
    
    image.png

    图中空出的部分,即为导航条UINavigationBar。此时计算frame应从导航栏下部为0开始计算,或者说控件会被下压64。
    不过我们一般不会使用到这一条,因为半透明效果比较好看啊~

    3.extendedLayoutIncludesOpaqueBars:Bool 不透明的条下是否可以扩展
      很明显,这条需要与上一条translucent搭配使用的,默认为NO,也就是不可以扩展。当translucent设置为NO,即导航栏UINavigationBar不透明的时候,默认不能扩展。若我们设置为YES,则会出现这种情况:


    image.png

    我并没有改变红色view的frame,而是被不透明的导航条盖住看不到了。很明显此时计算frame又是从屏幕最上方作为0开始计算了。
    为了计算究竟是在电源条下方还是屏幕最上方作为y的0点,改变了红色view的height为64和65重复试验,结果如下


    image.png
    结论是从屏幕上方作为y的0开始计算。
    不过第2条都很少用,第3条使用的几率...

    4.automaticallyAdjustsScrollViewInsets:Bool 自动校准滚动视图的嵌入视图
    这个其实就很简单了,也是我们最常使用的一个吧。automaticallyAdjustsScrollViewInsets是一个bool类型,默认为YES,也就是会自动校准滚动视图的嵌入视图。不过这个只针对于UIScrollView及其子视图,所以我们是用UITextView做一下测试。

    创建了一个frame为(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)占据整个屏幕的UITextView,并放置了足够多的文字。在默认automaticallyAdjustsScrollViewInsets为YES的前提下,我们测试下可能出现的结果。


    image.png

    似乎什么毛病都没有啊很正常啊。但是不要忘记我设置的frame的y是0啊。那大家可能就好奇了,难道UIScrollView的滚动视图的frame是从导航栏下边界算起的?不忙,我们设置automaticallyAdjustsScrollViewInsets为NO再试试。

    [self setAutomaticallyAdjustsScrollViewInsets:NO];
    
    image.png

    这个是一启动就出现的界面,我并没有向上滑动它的内容区域,也就是说,似乎此时的frame又是从屏幕下方开始的了。
    不要慌,我们改一下设置试试看。
    我将UITextView的frame设置为(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height),也就是y改成了64;然后改变了它的背景颜色为红色redColor;最后将[self setAutomaticallyAdjustsScrollViewInsets:NO];这行代码注掉,让它默认为YES。
    看一下效果。


    image.png

    注意:导航栏是半透明的,所以不存在被压到红色看不到的问题,也就是说,UITextView的frame的y的64的位置,是导航栏下方;那么0自然就是在屏幕下方开始计算了。
    很明显,automaticallyAdjustsScrollViewInsets改变的并不是UIScrollView的frame,而是它的内容区域contentView的可滚动区域,也就是scrollIndicatorInsets。这是我们能滚到的最大范围。相当于scrollIndicatorInsets这个属性UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>)的值从UIEdgeInsetsMake(0, 0, 0, 0)变为了UIEdgeInsetsMake(64, 0, 0, 0)。这就是automaticallyAdjustsScrollViewInsets这个属性的作用。
    另外再说一点,这个automaticallyAdjustsScrollViewInsets的属性,只对加在self.view上的第一个子视图起作用,所以我们可以在将UIScrollView加载到self.view上之前先加载一个其他控件,这样也能达到同样的效果。
    ps:

    当升级到iOS 11的时候,发现UIScrollView 有莫名其妙的偏移了 可是明明设置了
    
    automaticallyAdjustsScrollViewInsets
    
    这是因为iOS 11为UIScrollView 添加了新的属性contentInsetAdjustmentBehavior 这是一个枚举
    
    找到UIScrollViewContentInsetAdjustmentNever 从来不自动调整和automaticallyAdjustsScrollViewInsets = NO 是一个功效 这样就解决了iOS 11这个bug
    
            if (@available(iOS 11.0, *)) {
    
                Scrollview.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    
            } else {
    
                // Fallback on earlier versions
    
            }
    

    相关文章

      网友评论

        本文标题:iOS-与导航栏下控件的frame相关的edgesForExte

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