iOS 11 安全区域适配总结

本文主要是对iOS 11下APP中tableView
内容下移20pt或下移64pt的问题适配的一个总结。内容包括五个部分:问题的原因分析、adjustContentInset
属性的计算方式、什么情况下的tableView
会发生内容下移、有哪些解决方法、解决这个问题时遇到的另外一个小问题。
一、iOS 11下APP中tableView内容下移20pt或下移64pt的原因分析
问题如下图所示:


问题.png

问题.png

  1. 原因分析
    原因是iOS 11中Controller的automaticallyAdjustsScrollViewInsets
    属性被废弃了,所以当tableView超出安全区域时系统自动调整了SafeAreaInsets
    值,进而影响adjustedContentInset
    值,在iOS 11中决定tableView的内容与边缘距离的是adjustedContentInset
    属性,而不是contentInset
    。adjustedContentInset
    的计算方式见本文第二部分内容。因为系统对adjustedContentInset
    值进行了调整,所以导致tableView的内容到边缘的距离发生了变化,导致tableView下移了20pt(statusbar高度)或64pt(navigationbar高度)。
    如果你的APP中使用的是自定义的navigationbar,隐藏掉系统的navigationbar,并且tableView的frame为(0,0,SCREEN_WIDTH, SCREEN_HEIGHT)开始,那么系统会自动调整SafeAreaInsets值为(20,0,0,0),如果使用了系统的navigationbar,那么SafeAreaInsets
    值为(64,0,0,0),如果也使用了系统的tabbar,那么SafeAreaInsets
    值为(64,0,49,0)。关于什么情况下会发生内容下移的问题,本文第三部分有介绍。
  2. 安全区域的概念
    系统自动调整tableView内容偏移量,是根据安全区域来调整的。安全区域是iOS 11新提出的,如下图所示:


    SafeArea of an interface.png

    SafeArea of an interface.png

安全区域帮助我们将view放置在整个屏幕的可视的部分。即使把navigationbar设置为透明的,系统也认为安全区域是从navigationbar的bottom开始的。安全区域定义了view中可视区域的部分,保证不被系统的状态栏、或父视图提供的view如导航栏覆盖。可以使用additionalSafeAreaInsets
去扩展安全区域去包括自定义的content在你的界面。每个view都可以改变安全区域嵌入的大小,Controller也可以。
safeAreaInsets
属性反映了一个view距离该view的安全区域的边距。对于一个Controller的根视图而言,SafeAreaInsets
值包括了被statusbar
和其他可视的bars覆盖的区域和其他通过additionalSafeAreaInsets
自定义的insets值。对于view层次中得其他view,SafeAreaInsets
值反映了view被覆盖的部分。如果一个view全部在它父视图的安全区域内,则SafeAreaInsets
值为(0,0,0,0)。
二、 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
决定。有以下几种计算方式:
UIScrollViewContentInsetAdjustmentAutomatic
:如果scrollview在一个automaticallyAdjustsScrollViewInsets = YES的controller上,并且这个Controller包含在一个navigation controller中,这种情况下会设置在top & bottom上 adjustedContentInset = safeAreaInset + contentInset不管是否滚动。其他情况下与UIScrollViewContentInsetAdjustmentScrollableAxes
相同

UIScrollViewContentInsetAdjustmentScrollableAxes
: 在可滚动方向上adjustedContentInset = safeAreaInset + contentInset,在不可滚动方向上adjustedContentInset = contentInset;依赖于scrollEnabled和alwaysBounceHorizontal / vertical = YES,scrollEnabled默认为yes,所以大多数情况下,计算方式还是adjustedContentInset = safeAreaInset + contentInset

UIScrollViewContentInsetAdjustmentNever
: adjustedContentInset = contentInset

UIScrollViewContentInsetAdjustmentAlways
: adjustedContentInset = safeAreaInset + contentInset

当contentInsetAdjustmentBehavior
设置为UIScrollViewContentInsetAdjustmentNever的时候,adjustContentInset值不受SafeAreaInset
值的影响。
三、什么情况下的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}

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

  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
属性的,推荐使用这种方式。

  1. 通过设置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
    值。
    五、遇到的另外一个与安全区域无关的tableView内容下移的问题
    我的作品页面的tableView下移了约40pt,这里是否跟安全区域有关呢?
    查了下页面结构,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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容