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

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

一、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. 原因分析

原因是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,SCREENWIDTH, SCREENHEIGHT)开始,那么系统会自动调整SafeAreaInsets值为(20,0,0,0),如果使用了系统的navigationbar,那么SafeAreaInsets值为(64,0,0,0),如果也使用了系统的tabbar,那么SafeAreaInsets值为(64,0,49,0)。关于什么情况下会发生内容下移的问题,本文第三部分有介绍。

2. 安全区域的概念

系统自动调整tableView内容偏移量,是根据安全区域来调整的。安全区域是iOS 11新提出的,如下图所示:

http://img.blog.csdn.net/20170926100519768?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGVuY2VudF9CdWdseQ/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA/dissolve/70/gravity/SouthEast

安全区域帮助我们将view放置在整个屏幕的可视的部分。即使把navigationbar设置为透明的,系统也认为安全区域是从navigationbar的bottom开始,保证不被系统的状态栏、或导航栏覆盖。可以使用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决定。有以下几种计算方式:

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值的影响。

三、什么情况下的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属性的,推荐使用这种方式。

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值。

五、遇到的另外一个与安全区域无关的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;

《iOS 11 安全区域适配总结》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. Oracle-05:伪表dual

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 此乃这张表里的全部字段信息,此表无法做修改操作 为什么有伪表这个概念?????????? 因为sql92的一个 ...

  2. MIT KIT OpenID Connect Demo Client

    Hello world! You are NOT currently logged in. This example application is configured with several pa ...

  3. 为什么选择Spring Boot作为微服务的入门级微框架

    摘要:1. Spring Boot是什么,解决哪些问题 1) Spring Boot使编码变简单 2) Spring Boot使配置变简单 3) Spring Boot使部署变简单 4) Spring ...

  4. rename_windows.go

    {         if err != nil {             return err         }         return syscall.EINVAL     }     r ...

  5. 本地广播 localBroadcastManager Android

    使用localBroadcastManager发出的广播只能在本应用程序的内部进行传递. App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App. 相比于全局广播(普通广播),A ...

  6. 【bzoj 1407】【Noi2002】Savage

    Description Input 第1行为一个整数N(1<=N<=15),即野人的数目. 第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴 ...

  7. sql中1=1的and和or问题

    SELECT *  FROM mentor_teacher WHERE 1 = 1  AND status = ? limit 0, 10 sql语句中如果有1=1的问题, 那么,如果是and并且的关 ...

  8. 基于SDRAM的视频图像采集系统

    本文是在前面设计好的简易SDRAM控制器的基础上完善,逐步实现使用SDRAM存储视频流数据,实现视频图像采集系统,CMOS使用的是OV7725. SDRAM控制器的完善 1. 修改SDRAM的时钟到1 ...

  9. 查看keras自动给文件夹标号

    from tensorflow.contrib.keras.api.keras.preprocessing.image import ImageDataGenerator,img_to_array f ...

  10. sum() 函数性能堪忧,列表降维有何良方?

    本文原创并首发于公众号[Python猫],未经授权,请勿转载. 原文地址:https://mp.weixin.qq.com/s/mK1nav2vKykZaKw_TY-rtw Python 的内置函数 ...