适配iOS 11及iPhoneX iOS 11下tableView内容下移的问题

一.为什么会发生内容下移

1.原因分析

 
   
在iOS 11中Apple干掉了ViewController中的automaticallyAdjustsScrollViewInsets这个属性,当tableview的frame超出了安全区域后系统会自动的调整SafeAreaInsets的值,而iOS 11中真正影响tableview内容与边缘的变成了adjustedContentInset而不是以前的contentInset。由于系统对adjustedContentInset进行了调整导致了tableView的内容到边缘的距离发生了变化,下移距离分别是20pt(没有navigationBar,下移了一个statusBar的高度),64pt(navigationBar的高度以及statusBar的高度)。

2.关于安全区域

安全区域的概念是在iOS 11提出的,如图
适配iOS 11及iPhoneX iOS 11下tableView内容下移的问题_第1张图片
 
   

简单来说下什么是安全区域,就是把View放在整个屏幕的可视部分,当有navigationbar存在时安全区域也是从navigationbar的bottom开始的,若同时存在tabBar则中间区域为安全区域,ViewController中还提供了additionalSafeAreaInsets去扩展安全区域。

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

二、 adjustContentInset

在iOS11中scrollView新增的两个属性:adjustContentInset和contentInsetAdjustmentBehavior。
 
   

adjustContentInset表示contentView.frame.origin偏移了scrollview.frame.origin多少;是系统计算得来的,计算方式由contentInsetAdjustmentBehavior决定。有以下几种计算方式:

UIScrollViewContentInsetAdjustmentAutomatic:如果scrollview在一个automaticallyAdjustsScrollViewContentInset = 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何时会发生偏移问题

 
   
最常见的场景:tableview的frame超出了安全区域,而且设置了tableview的contentInset,第一幅图中的tableview的frame设置为(0,0,self.view.frame.size.width,self.view.frame.size.height),contentInset设置为UIEdgeInsetsMake(64,0,0,0);从而导致了adjustedContentInset 偏移了一个safeAreaInset + contentInset,简单来说:当tableview的frame超出安全区域之后,系统会自动调整tableview的显示范围,但此时又设置了contentInset属性导致出现下移现象。

四、解决方案

1.去掉contentInset

因为在iOS 11中系统已经默认对scrollview的显示做了处理只要其超过安全区域,它的内容显示都会在view上正常显示,所以就不需要设置contentInset,避免发生偏移

2.设置contentInsetAdjustmentBehavior

 
   
在不改变contentInset的情况下通过设置tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;让adjustContentInset值不受SafeAreaInset值的影响。

3. iOS 11 ViewController新增的属性 addtionalSafeAreaInset;

 
   
在不改变contentInset的情况下通过增加安全区域的范围来抵消掉SafeAreaInset的值,如果SafeAreaInset值为(20,0,0,0),那么设置additionalSafeAreaInsets属性值为(-20,0,0,0),则SafeAreaInsets不会对adjustedContentInset值产生影响

4.把tableview的frame控制在安全区域内且不设置contentInset

 
   

在我的项目中对基类控制器中添加了一个ContentView属性,该View的区域范围也就是安全区域的范围,需要做的就是先算出View的高度,把tableview放到安全区域内就可以了,这样也有个好处就是,iOS 11只对scrollview进行了安全区域的显示处理,如果是view的话超出安全区域外的内容是无法显示的。

这里说一下automaticallyAdjustsScrollViewInsets这个属性,在iOS 11之前即使把tableview放到了可视范围之内(有NavigationBar且没有设置contentInset),当该属性为YES时候tableview还是会发生偏移。。。(很尴尬,所以这个属性我一般至为NO,瞬间觉得iOS 11做了一件很美好的事情)

对于安全区域高度的计算有必要说一下,仅在竖屏有NavigationBar的情况下,传统的iPhone尺寸安全区域高度为SCREEN_HEIGHT-64 ;而iPhoneX中为SCREEN_HEIGHT-(44+44+34),(第一个44为iPhoneX状态栏的高度,第二个为NavigationBar的高度,第三个为底部非安全区域的高度,iPhoneX比较特殊,并且WWDC上有明确说明对iPhoneX上view的显示必须放在安全区域之内)。



你可能感兴趣的:(IOS开发,项目中用到的方法总结)