《iOS 11 安全区域适配总结》

本文来自于腾讯Bugly公众号(weixinBugly),做者:sonialiu,未经做者赞成,请勿转载,原文地址:http://mp.weixin.qq.com/s/W1_0VrchCO50owhJNmJnuQjava

| 导语 本文主要是对iOS 11下企鹅 FM APP中tableView内容下移20pt或下移64pt的问题适配的一个总结。内容包括五个部分:问题的缘由分析、adjustContentInset属性的计算方式、什么状况下的tableView会发生内容下移、有哪些解决方法、解决这个问题时遇到的另一个小问题。ios

1、iOS 11下APP中tableView内容下移20pt或下移64pt的缘由分析

问题以下图所示:
http://img.blog.csdn.net/20170926095658997?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGVuY2VudF9CdWdseQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast安全

1. 缘由分析app

缘由是iOS 11中Controller的automaticallyAdjustsScrollViewInsets属性被废弃了,因此当tableView超出安全区域时系统自动调整了SafeAreaInsets值,进而影响adjustedContentInset值,在iOS 11中决定tableView的内容与边缘距离的是adjustedContentInset属性,而不是contentInset。adjustedContentInset的计算方式见本文第二部份内容。由于系统对adjustedContentInset值进行了调整,因此致使tableView的内容到边缘的距离发生了变化,致使tableView下移了20pt(statusbar高度)或64pt(navigationbar高度)。atom

若是你的APP中使用的是自定义的navigationbar,隐藏掉系统的navigationbar,而且tableView的frame为(0,0,SCREENWIDTH, SCREENHEIGHT)开始,那么系统会自动调整SafeAreaInsets值为(20,0,0,0),若是使用了系统的navigationbar,那么SafeAreaInsets值为(64,0,0,0),若是也使用了系统的tabbar,那么SafeAreaInsets值为(64,0,49,0)。关于什么状况下会发生内容下移的问题,本文第三部分有介绍。.net

2. 安全区域的概念code

系统自动调整tableView内容偏移量,是根据安全区域来调整的。安全区域是iOS 11新提出的,以下图所示:
http://img.blog.csdn.net/20170926100519768?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGVuY2VudF9CdWdseQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEastblog

安全区域帮助咱们将view放置在整个屏幕的可视的部分。即便把navigationbar设置为透明的,系统也认为安全区域是从navigationbar的bottom开始,保证不被系统的状态栏、或导航栏覆盖。可使用additionalSafeAreaInsets去扩展安全区域使它包括自定义的content在界面上。每一个view均可以改变安全区域嵌入的大小,Controller也能够。it

safeAreaInsets属性反映了一个view距离该view的安全区域的边距。对于一个Controller的根视图而言,SafeAreaInsets值包括了被statusbar和其余可视的bars覆盖的区域和其余经过additionalSafeAreaInsets自定义的insets值。view层次中的其它view,SafeAreaInsets值反映了该view被覆盖的部分。若是一个view所有在它父视图的安全区域内,则SafeAreaInsets值为(0,0,0,0)。io

2、 adjustContentInset属性的计算方式

首先看scrollView在iOS11新增的两个属性:adjustContentInset 和 contentInsetAdjustmentBehavior。

/* Configure the behavior of adjustedContentInset.

Default is UIScrollViewContentInsetAdjustmentAutomatic.
*/@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior
adjustContentInset表示contentView.frame.origin偏移了scrollview.frame.origin多少;是系统计算得来的,计算方式由contentInsetAdjustmentBehavior决定。有如下几种计算方式:

1.UIScrollViewContentInsetAdjustmentAutomatic:若是scrollview在一个automaticallyAdjustsScrollViewContentInset = YES的controller上,而且这个Controller包含在一个navigation controller中,这种状况下会设置在top & bottom上 adjustedContentInset = safeAreaInset + contentInset不论是否滚动。其余状况下与UIScrollViewContentInsetAdjustmentScrollableAxes相同

2.UIScrollViewContentInsetAdjustmentScrollableAxes: 在可滚动方向上adjustedContentInset = safeAreaInset + contentInset,在不可滚动方向上adjustedContentInset = contentInset;依赖于scrollEnabled和alwaysBounceHorizontal / vertical = YES,scrollEnabled默认为yes,因此大多数状况下,计算方式仍是adjustedContentInset = safeAreaInset + contentInset

3.UIScrollViewContentInsetAdjustmentNever: adjustedContentInset = contentInset

4.UIScrollViewContentInsetAdjustmentAlways: adjustedContentInset = safeAreaInset + contentInset

当contentInsetAdjustmentBehavior设置为UIScrollViewContentInsetAdjustmentNever的时候,adjustContentInset值不受SafeAreaInset值的影响。

3、什么状况下的tableView会发生上述问题

若是设置了automaticallyAdjustsScrollViewInsets = YES,那么不会发生问题,一直都是由系统来调整内容的偏移量。

接下来排查下本身的项目中哪些页面会发生以上问题。

当tableView的frame超出安全区域范围时,系统会自动调整内容的位置,SafeAreaInsets值会不为0,因而影响tableView的adjustContentInset值,因而影响tableView的内容展现,致使tableView的content下移了SafeAreaInsets的距离。SafeAreaInsets值为0时,是正常的状况。

须要了解每一个页面的结构,看tableView是否被系统的statusbar或navigationbar覆盖,若是被覆盖的话,则会发生下移。也能够经过tableview.safeAreaInsets的值来确认是由于安全区域的问题致使的内容下移。

以下代码片断,能够看出系统对tableView向下调整了20pt的距离,由于tableView超出了安全区域范围,被statusbar覆盖。

tableview.contentInset: {64, 0, 60, 0}

tableview.safeAreaInsets: {20, 0, 0, 0}

tableview.adjustedContentInset: {84, 0, 60, 0}

4、这个问题的解决方法有哪些?

1. 从新设置tableView的contentInset值,来抵消掉SafeAreaInset值,由于内容偏移量 = contentInset + SafeAreaInset;

若是以前本身设置了contentInset值为(64,0,0,0),如今系统又设置了SafeAreaInsets值为(64,0,0,0),那么tableView内容下移了64pt,这种状况下,能够设置contentInset值为(0,0,0,0),也就是听从系统的设置了。

2. 设置tableView的contentInsetAdjustmentBehavior属性

若是不须要系统为你设置边缘距离,能够作如下设置:

//若是iOS的系统是11.0,会有这样一个宏定义“#define __IPHONE_11_0  110000”;若是系统版本低于11.0则没有这个宏定义#ifdef __IPHONE_11_0   
if ([tableView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
    tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
#endif

contentInsetAdjustmentBehavior属性也是用来取代automaticallyAdjustsScrollViewInsets属性的,推荐使用这种方式。

3. 经过设置iOS 11新增的属性addtionalSafeAreaInset;

iOS 11以前,你们是经过将Controller的automaticallyAdjustsScrollViewInsets属性设置为NO,来禁止系统对tableView调整contentInsets的。若是仍是想从Controller级别解决问题,那么能够经过设置Controller的additionalSafeAreaInsets属性,若是SafeAreaInset值为(20,0,0,0),那么设置additionalSafeAreaInsets属性值为(-20,0,0,0),则SafeAreaInsets不会对adjustedContentInset值产生影响,tableView内容不会显示异常。这里须要注意的是addtionalSafeAreaInset是Controller的属性,要知道SafeAreaInset的值是由哪一个Controller引发的,多是由本身的Controller调整的,多是navigationController调整的。是由哪一个Controller调整的,则设置哪一个Controller的addtionalSafeAreaInset值来抵消掉SafeAreaInset值。

5、遇到的另一个与安全区域无关的tableView内容下移的问题

个人做品页面的tableView下移了约40pt,这里是否跟安全区域有关呢?
http://img.blog.csdn.net/20170926100650727?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGVuY2VudF9CdWdseQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

查了下页面结构,tableView的父视图的frame在navigationbar的bottom之下,tableView在父视图的安全区域内,打印出来tableView的SafeAreaInset值也是(0,0,0,0);因此不是安全区域致使的内容下移。

通过查看代码,发现tableView的style:UITableViewStyleGrouped类型,默认tableView开头和结尾是有间距的,不须要这个间距的话,能够经过实现heightForHeaderInSection方法(返回一个较小值:0.1)和viewForHeaderInSection(返回一个view)来去除头部的留白,底部同理。

iOS 11上发生tableView顶部有留白,缘由是代码中只实现了heightForHeaderInSection方法,而没有实现viewForHeaderInSection方法。那样写是不规范的,只实现高度,而没有实现view,但代码这样写在iOS 11以前是没有问题的,iOS 11以后应该是因为开启了估算行高机制引发了bug。添加上viewForHeaderInSection方法后,问题就解决了。或者添加如下代码关闭估算行高,问题也获得解决。

self.tableView.estimatedRowHeight = 0;

self.tableView.estimatedSectionHeaderHeight = 0;

self.tableView.estimatedSectionFooterHeight = 0;
相关文章
相关标签/搜索