前言
iOS 11正式版将于9月19号正式推送,作为开发者当然不会等到正式版推出之后才去体验最新版的iOS 11,于是最近几天安装了下XCode9,在模拟器上跑了一下自己的App,发现了一些问题,本文主要谈一下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提出的,如图
SafeArea简单来说下什么是安全区域,就是把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的显示必须放在安全区域之内)。
五、一些体会
最近看了很多WWDC17的视频,Swift4越来越稳定、XCode9以及iOS 11的变化真的很大而且充满很多新的特性,XCode9支持了无线调试、断电增强等功能开发起来越来越方便,iOS 11的众多新功能ARKit、Core ML等,让AR技术、机器学习和人工智能离我们越来越近。作为一名开发者来说最好的成长就是不断的填坑,本文借鉴了一些http://www.jianshu.com/p/efbc8619d56b文中的内容对此表示感谢,最后附上WWDC关于iPhoneX对于SafeArea的介绍:developer.apple.com/videos/play/fall2017/801/
网友评论