iOS开发-适配iOS 11及iPhoneX(1)

作者: JackChen的简书 | 来源:发表于2017-09-15 23:04 被阅读14184次

    前言

    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/

    相关文章

      网友评论

      • Maj_sunshine:我想问下我升了xcode9,不适配iphonex能上架么。因为好像safeArea只能在iOS9以上,在iOS8用不了,或者有什么解决办法么
        JackChen的简书:@学污直径 storyboard中有safeArea区域,拖控件时候注意下即可,你所说的纯代码重写xib和storyboard是什么意思?
        Maj_sunshine:storyboard开启safeArea就必须iOS9以上,代码的话是我重写所有xib和storyboard么:fearful:
        JackChen的简书:@学污直径 进行版本判断,iPhoneX放到safeArea中
      • _码奴:大神知道纯代码编写的界面怎么适配安全区域吗
        直持小崔:@JackChen的简书 我已经用的xib 了 直接最低iOS9 这样的话 就不存在适配问题了吗 因为已经利用了 苹果的安全区域的遍历 是这样吗 我的理解 而且我也做了一个demo 貌似是对的 而且现在布局的话 默认xib 是默认相对于安全区域 0 0 0 0的
        _码奴:@JackChen的简书 我又看了一遍,你的意思是说,还是需要通过代码设置frame来手动适配安全区域吗,其实我是想把之前的一个写了两年的项目适配安全区域,里面部分界面和View的布局是用纯代码写的,我知道你们对于这样的情况是怎么适配的,我现在是在改部分View控件的frame来适配安全区域问题的,但是要一个一个控件找,太麻烦了
        JackChen的简书:@_码奴 我写的很清楚了,纯代码下需要考虑safeArea问题,需要把控件放在安全区域内就可以了。
      • 我本善良:分析的很好,受教了
      • da2343deb340:adjustedContentInset = safeAreaInset + contentInset 这个具体是什么意思啊
        JackChen的简书:@远冬 adjustedContentInset 是新增的属性它的值由safeAreaInset 和原本的contentInset 共同组成,简单来说就是原来scrollview的偏移不单单由content inset组成了,是由上面两个共同决定

      本文标题:iOS开发-适配iOS 11及iPhoneX(1)

      本文链接:https://www.haomeiwen.com/subject/pxlrdttx.html