iOS——iPhone X适配实战总结

最近公司项目需要开始适配iPhone X了,之前在网上看到过很多讲解iPhone X适配的文章,也刷过几篇文章看了一遍,但是看完之后实在受不了各种假帖。甚至讲的都是一些理论和差异上的东西,真正讲解实际开发中适配iPhone的并没有多少,有些看完正片文章之后都不知道怎么开始。

于是自己去根据官方提供的资料和指南写一篇只针对iPhone X适配的贴子……

前言:
  1. 本文从实际开发着手iPhone X适配,关于相关理论与常识内容不会过多解释。
  2. 本文会分析iPhone X适配的几个不同方向和相关的处理方案
  3. 本文会分析并总结适配和测试过程中遇到的Bug,最终给出实际的适配方案或者代码
  4. 本文会尽量多的从实际项目与实际适配步骤会代码进行介绍
官方资料

HIG-Human Interface Guideline
官方Session

首先我们要明确一点:
iPhone X适配的宗旨:我们要做的是让那些不能被遮挡的内容和控件在安全区域范围内显示,

一.iPhone X的规则

| | |

  1. iPhone X是真正的3x标准,印象中7p是2.88x
  2. iPhone X宽度和4.7的6,7,8一致(375),高度多出145pt(+20%)
  3. iPhone X的比例是9:19.5,而4.7的6,7,8比例是9:16,
  4. iPhone X(375812->11252436->5.8英寸)Super Retina
  5. 状态栏20->44(留海H=30,W=209,耳朵W=83),底脚0->34
  6. 实际上可有效利用的高度为:145 – 24 (Status Bar) – 34 (Home Indicator) = 87pt
  7. 键盘高度由 216pt 增长为 291pt,设计文字区域时要小心
  8. Home Indicator,Tab Bar 高度由 49pt 增长为 83pt
  9. 横屏时Home Indicator的高度为21pt,需要格外注意

| | |

iPhone X竖屏时占满整个屏幕的控制器的view的safeAreaInsets是(44,0,34,0),横屏是(0,44,21,44),inset后的区域正好是safeAreaLayoutGuide区域

如果你的 UI「顶部」有 Navigation Bar 或其它类似的UI控件,那么一般来说,在设计稿将 Navigation Bar 的背景色往上延伸 44pt,「垫在 Status Bar 后方」作为背景色即可
如果你的 UI「底部」有 Tab Bar、Toolbar 或其它类似的UI控件,在设计稿时将背景色往下延伸 34pt,「垫在 Home Indicator 后方」作为背景色即可。

二: iOS11相关

  1. 如果只是设置了titleView,没有设置barbutton,把titleview的宽度设置为屏幕宽度,则titleview距离屏幕的边距,iOS11之前,在iPhone6p上是20p,在iPhone6p之前是16p;iOS11之后,在iPhone6p上是12p,在iPhone6p之前是8p。

  2. 如果只是设置了barbutton,没有设置titleview,则在iOS11里,barButton距离屏幕的边距是20p和16p;在iOS11之前,barButton距离屏幕的边距也是20p和16p。

  3. 如果同时设置了titleView和barButton,则在iOS11之前,titleview和barbutton之间的间距是6p,在iOS11上titleview和barbutton之间无间距

  4. estimatedRowHeight是一个预估高度,iOS11之前是为0,在iOS11下,这个值默认为44。

  5. iOS11以前,我们布局时, 视图的 top 和 bottom 一般参照的是 Top Layout Guide 和 Bottom Layout Guide

  6. iOS11为UIViewController和UIView增加了两个新的属性safeAreaInsets和safeAreaLayoutGuide, 通过这两个属性我们可以获得安全区域的范围

    safeAreaInsets 适用于手动计算.
    safeAreaLayoutGuide 适用于自动布局.
    

三. iPhone环境判断

  • 通过分辨率判断:
    #define kDevice_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
    
  • 通过设备名称判断:
    @"iPhone10,1" : @"iPhone 8",
    @"iPhone10,4" : @"iPhone 8",
    @"iPhone10,2" : @"iPhone 8 Plus",
    @"iPhone10,5" : @"iPhone 8 Plus",
    @"iPhone10,3" : @"iPhone X",
    @"iPhone10,6" : @"iPhone X",
    
  • 判断状态栏的高度(如果状态栏没有隐藏,且竖屏的情况)
  • 判断屏幕的高度或者宽度(横屏的时候)
  • 根据是否可执行或者获取对应API的值(safeAreaInseret)
  • 根据系统框架
常用宏定义
#define IS_IPHONE_X_HEIGHT         ([[UIScreen mainScreen] bounds].size.height >= 812.0f ? 812.0f : 667.0f)
#define ScaleWidth(width)           width/ 375.0*KSCREEN_WIDTH
#define ScaleHeigth(height)           height/IS_IPHONE_X_HEIGHT*KSCREEN_HEIGHT
#define WKSW(width)           width/375.0*KSCREEN_WIDTH
#define WKSH(height)           height/IS_IPHONE_X_HEIGHT*KSCREEN_HEIGHT
#define SafeAreaTopHeight (kWJScreenHeight == 812.0 ? 88 : 64)
#define VIEWSAFEAREAINSETS(view) ({UIEdgeInsets i; if(@available(iOS 11.0, *)) {i = view.safeAreaInsets;} else {i = UIEdgeInsetsZero;} i;})
VIEWSAFEAREAINSETS(view).left
VIEWSAFEAREAINSETS(self.view).right

四.启动页的适配

启动页的启动方式

  • LaunchScreen(这里直接设置图片就可以)
  • LaunchImage

使用对应的设计图片:1125 * 2436

如果使用的是Assets中的LaunchImage, 在增加了iPhone X尺寸的图片配置.
准备一张尺寸:1125 * 2436的启动图片, 移动到LaunchImage的Finder目录中, 并在LaunchImage中的Contents.json文件中增加 (注意Json格式):

{
    "extent" : "full-screen",
    "idiom" : "iphone",
    "subtype" : "2436h",
    "filename" : "图片名.png",
    "minimum-system-version" : "11.0",
    "orientation" : "portrait",
    "scale" : "3x"
}

五.刷新框架的适配iOS11

这里拿最有名的刷新框架,如果使用的类似的刷新框架并且隐藏导航那么你或许会遇到:刷新控件和留海重合且被挡住

具体原因:
iOS 11上面废除了automaticallyAdjustsScrollViewInsets,使用contentInsetAdjustmentBehavior代替

适配具体代码:

if (@available(iOS 11.0, *)) {
    self.home_collectionView.contentInsetAdjustmentBehavior = UIApplicationBackgroundFetchIntervalNever;
} else {
    self.automaticallyAdjustsScrollViewInsets = false;
    // Fallback on earlier versions
}
宏定义:
/// 第一个参数是当下的控制器适配iOS11 一下的,第二个参数表示scrollview或子类
#define AdjustsScrollViewInsetNever(controller,view) if(@available(iOS 11.0, *)) {
    view.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else if([controller isKindOfClass:[UIViewController class]]) {
    controller.automaticallyAdjustsScrollViewInsets = false;
}

六:导航栏

在iOS11导航栏多了一个LargeTitleView,专门显示大字标题用的,整个导航栏的高度达到了96p,这不包括状态栏的高度,也就是说,整个app顶部高度达到了116p,其中statusbar=20,title=44,largetitle=52,不过默认是64p;

  • 当然,iPhoneX的高度会更高点,如果不显示大字标题,顶部的高度也达到了88,statusbar=44,title=44,如果显示大字标题,则高度变成了140,statusbar=44,title=44,largetitle=52,也就是说,iPhoneX的刘海高度为24p,

七:导航栏按钮间距变化(UIBarButtonItem) (iPhoneX & iOS 11)

iOS11以后,导航栏的层级发生了变化,也无法时使导航栏左右按钮边距为0了

iOS11之前导航栏的title是添加在UINavigationItemView上面,而navigationBarButton则直接添加在UINavigationBar上面,如果设置了titleView,则titleView也是直接添加在UINavigationBar上面。iOS11之后,大概因为largeTitle的原因,视图层级发生了变化,如果没有给titleView赋值,则titleView会直接添加在_UINavigationBarContentView上面,如果赋值了titleView,则会把titleView添加在_UITAMICAdaptorView上,而navigationBarButton被加在了_UIButtonBarStackView上,然后他们都被加在了_UINavigationBarContentView上

所以如果你的项目是自定义的navigationBar,那么在iOS11上运行就可能出现布局错乱的bug,解决办法是重写UINavigationBar的layoutSubviews方法,调整布局,上代码:

- (void)layoutSubviews {
    [super layoutSubviews];
    //注意导航栏及状态栏高度适配
    self.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), naviBarHeight);
    for (UIView *view in self.subviews) {
        if([NSStringFromClass([view class]) containsString:@"Background"]) {
            view.frame = self.bounds;
        }
        else if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {
            CGRect frame = view.frame;
            frame.origin.y = statusBarHeight;
            frame.size.height = self.bounds.size.height - frame.origin.y;
            view.frame = frame;
        }
    }
}

看了简书App适配iOS11发现titleView支持autolayout,这要求titleView必须是能够自撑开的或实现了- intrinsicContentSize方法

- (CGSize)intrinsicContentSize {
    return UILayoutFittingExpandedSize;
}
  1. 导航栏新增了一种大标题样式,默认设置是不开启,所以不需要修改。
  2. titleView支持autolayout,这要求titleView必须是能够自撑开的或实现了- intrinsicContentSize,

App需要实现导航栏左右按钮边距为0

八:继承自UIScrollView的视图偏移问题

在iOS11设备上运行出现最多问题应该就是tableview莫名奇妙的偏移20pt或者64pt了。。原因是iOS11弃用了automaticallyAdjustsScrollViewInsets属性(前面有提到),取而代之的是UIScrollView新增了contentInsetAdjustmentBehavior属性,这一切的罪魁祸首都是新引入的safeArea,

原因分析

原因是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)

if (@available(iOS 11.0, *)) {
    self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
    self.automaticallyAdjustsScrollViewInsets = NO;
}

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

  • 重新设置tableView的contentInset值,来抵消掉SafeAreaInset值,因为内容下移偏移量 = contentInset + SafeAreaInset;

如果之前自己设置了contentInset值为(64,0,0,0),现在系统又设置了SafeAreaInsets值为(64,0,0,0),那么tableView内容下移了64pt,这种情况下,可以设置contentInset值为(0,0,0,0),也就是遵从系统的设置了。

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

  • 通过设置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值。

九:UITableView,cell,header,footer高度异常,tableView顶部有留白

在iOS 11中默认启用Self-Sizing,,Headers, footers, and cells都默认开启了Self-Sizing,所有estimated 高度默认值从iOS11之前的 0 改变为UITableViewAutomaticDimension
要解决此类异常的话,可通过以下代码解决

_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;

这个配合estimatedRowHeight、estimatedSectionFooterHeight、estimatedSectionHeaderHeight使用,可以预估高度。之前,设置header或者footer高度为0时,需要设置height=0.1,才会起作用,如果直接设置为0,则会使用默认高度。iOS11由于自动使用预估高度,所以,忽略了设置的高度,使原来的高度增大了。只要把这几个属性设置为0就可以解决

在iOS11里面有时候在tableView的头部和尾部留白,因为苹果给滚动试图加进去了self-sizeing,开始计算逐步计算contentSize,默认如果不去实现viewForHeaderInSection就不会调用heightForHeaderInSection,尾部试图一样。
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { }
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {   return 0.001 }

如果你不想实现viewForHeaderInSection也不想留白,那么只需要使用上面的三段代码把self-sizeing自动估高关闭即可

如果你使用了Masonry,某些界面需要适配需要适配safeArea,可以试试下面这段代码

if (@available(iOS 11.0, *)) {
    make.edges.equalTo()(self.view.safeAreaInsets)
} else {
    make.edges.equalTo()(self.view)
}

十:适配iOS 11 列表的册数删除

在iOS8之后,苹果官方增加了UITableVIew的右滑操作接口,即新增了一个代理方法(tableView: editActionsForRowAtIndexPath:)和一个类(UITableViewRowAction),代理方法返回的是一个数组,我们可以在这个代理方法中定义所需要的操作按钮(删除、置顶等),这些按钮的类就是UITableViewRowAction。

这个类只能定义按钮的显示文字、背景色、和按钮事件。并且返回数组的第一个元素在UITableViewCell的最右侧显示,最后一个元素在最左侧显示。从iOS 11开始有了一些改变,首先是可以给这些按钮添加图片了,然后是如果实现了以下两个iOS 11新增的代理方法,将会取代(tableView: editActionsForRowAtIndexPath:)代理方法:

注意:看的有的文章如果在iOS11上面调用老的删除,会崩溃,

- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?


func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let action = UIContextualAction(style: .destructive, title: "Delete") { 
    (action, view, handler) in
        handler(true)
    }

    let configuration = UISwipeActionsConfiguration(actions: [action])
    return configuration
}


func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let action = UIContextualAction(style: .normal, title: "Mark") { (action, view, handler) in
    handler(true)
    }
    action.backgroundColor = UIColor.init(red: 254/255.0, green: 175/255.0, blue: 254/255.0, alpha: 1);

    let configuration = UISwipeActionsConfiguration(actions: [action])
    return configuration
}

十一:到底用viewSafeAreaInsetsDidChange还是viewWillLayoutSubviews

先来看看下面一段代码,相信做过iPhone X适配的同学应该都不陌生,

var safeArea: CGFloat = 0
if #available(iOS 11.0, *) {
    safeArea += self.view.safeAreaInsets.bottom || UIApplication.shared.keyWindow.rootViewController.view.safeAreaInsets.bottom

}
coding ... constant || originY || frame || height

有时候,我们会发现这样的一段适配的代码,如果根据苹果的特性,和我们所了解情况,我们一般都会把他放到viewSafeAreaInsetsDidChange,
但是,并没有什么卵用,但是根据UI刷新的特性,我试着把他放在viewWillLayoutSubviews,却又正常了,很多人对此很是不解。

首先我们要知道:
  • viewSafeAreaInsetsDidChange调用时机很早,在viewWillAppear后

viewSafeAreaInsetsDidChange后面会调用两次viewDidLayoutSubviews,所以我们应该把改变高度或布局的代码都写在viewDidLayoutSubviews里,这样就不会有多余的动画效果了

注意: viewDidLayoutSubviews可能会由别的操作频繁触发,所以如果调整safeArea布局的代码比较耗时,可以考虑加上一个状态标记,只在didChange后执行一次布局调整

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    UIEdgeInsets safeAreaInsets = sgm_safeAreaInset(self.view);
    CGFloat height = 44.0; // 导航栏原本的高度,通常是44.0
    height += safeAreaInsets.top > 0 ? safeAreaInsets.top : 20.0; // 20.0是statusbar的高度,这里假设statusbar不消失
    if (_navigationbar && _navigationbar.height != height) {
        _navigationbar.height = height;
    }
}

十二:纯代码的宽高比适配

/// 高度系数 812.0 是iPhoneX的高度尺寸,667.0表示是iPhone 8 的高度,如果你觉的它会变化,那我也很无奈
#define kWJHeightCoefficient (kWJScreenHeight == 812.0 ? 667.0/667.0 : kWJScreenHeight/667.0)

| | |

十三:纯代码适配iPhone X脚底

首先需要知道一点的是,底部脚底高度是34(tabBar之下所拓张的区域)适配规则:

  • 列表页面不去适配,底部有按钮的界面要适配

viewSafeAreaInsetsDidChange方法里面打印NSLog(@”%@”,NSStringFromUIEdgeInsets(self.view.safeAreaInsets));

注意:

1.介绍viewSafeAreaInsetsDidChange方法系统调用或者你设置控制器的additionalSafeAreaInsets安全区域边界
2.顺序viewSafeAreaInsetsDidChange调用顺序实在viewWillAppear之后,在viewWillLayoutSubvies之前调用

/// 底部宏,吃一见长一智吧,别写数字了
#define SafeAreaBottomHeight (kWJScreenHeight == 812.0 ? 34 : 0)

十四:xib和SB适配

安全区域:整个屏幕–导航栏–状态栏–tabbar(自己设定的安全区域除外

xib的适配齐刘海和圆角,如果你们项目要求适配iOS 9一下的,就该一个一个好好拖,如果你们不要求适配iOS 9一下的,只需要给view打开安全区域。

十五:App Store评论跳转问题

在iOS11 之后,会跳的Today里面说无法连接到App Store

先来看看我们之前的写法

NSString *appstoreUrlString = [NSString stringWithFormat: @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%@",AppStoreAppId ];
NSURL * url = [NSURL URLWithString:appstoreUrlString];
if ([[UIApplication sharedApplication] canOpenURL:url]){
    [[UIApplication sharedApplication]openURL:url];
}else{
    WKLog(@"can not open");
}

到iOS 11后,那样已经没有效果了,要改成:

NSString *appstoreUrlString = [NSString stringWithFormat:@"itms-apps://itunes.apple.com/cn/app/idXXXXXX?mt=8&action=write-review", AppStoreAppId ];
NSURL * url = [NSURL URLWithString:appstoreUrlString];
if ([[UIApplication sharedApplication] canOpenURL:url]){
    [[UIApplication sharedApplication]openURL:url];
}else{
    WKLog(@"can not open");
}

十六:导航栏设置透明问题

本来导航栏设置为不透明,如今却变成了透明(磨砂)模式,要知道导航栏透明与不透明的区别除了视觉差异外还有对屏幕左上角坐标点(0,0)的基准是不一样的。

当导航栏设置为透明模式时—>基准点为手机屏幕最左上角,也就是说如果你在(0,0)点放一个有色label时,你就会发现导航栏是挡住了你的方块的,因为是半透明,你能隐约间看到有色块
如果你需要设置导航栏透明度,切记把

self.navigationController.navigationBar.translucent = NO;

写到ViewWillAppear里!

十七:twitter

今天刚发现的一个坑,那就是iOS11设置里并没有集成twitter等第三方应用了

一些系统的关于这些APP的API也申明被废弃了,并推荐使用官网SDK

iOS 11 no longer supports using Twitter through the built-in social framework.

]Instead,you can use Twitter Kit 3 to Tweet, log in users, and use the Twitter API.

所以APP里集成twitter分享同学要注意了,一定要检查下twitter分享功能。其它APP分享如Facebook,微博分享功能等应该是完好的。

十八:AppIcon

在iOS11上发现了一个奇怪的现象,APP在启动时图标会出现黑边,

原因是iOS11修改了App启动动画,如果你的App图标有圆角那么就会变成这个鸟样了…所有图标都换成直角就好了

十九:相册访问权限

iOS11上系统默认打开了用户相册的访问权限,但是当你保存图片时APP就会crash,

原因是需要在info.plist再申明一个NSPhotoLibraryAddUsageDescription的key,同时为了兼容iOS11以前的机型,保留以前NSPhotoLibraryUsageDescription的key

总结:

1. 属性总结:
  • self.additionalSafeAreaInsets
  • self.view.safeAreaInsets

self.additionalSafeAreaInsets 改变safeAreaInsets的值

  • self.viewSafeAreaInsetsDidChange()
  • self.view.safeAreaInsetsDidChange()
    - (void)viewSafeAreaInsetsDidChange在UIViewController中第一次调用的时间是在- (void)viewWillAppear:(BOOL)animated调用之后, 在- (void)viewWillLayoutSubviews调用之前.
    

当你的viewController改变了它的safeAreaInsets值时,有两种方式获取到回调

self.viewSafeAreaInsetsDidChange()
self.view.safeAreaInsetsDidChange()

  • self.view.safeAreaLayoutGuide

self.view.safeAreaLayoutGuide UIView的一个只读属性,作为参照物,让view可以相对某个view的safeAreaLayoutGuide做布局,从而保证view能正常、安全地显示(相对的那个view不一定要是父view)

把safeAreaLayoutGuide看成是一个“view”,这个“view”系统自动帮我们调整它的bounds,让它不会被各种奇奇怪怪的东西挡住,包括iPhone X的刘海区域和底部的一道杠区域,可以认为在这个“view”上一定能完整显示所有内容,safeAreaInsets来调整自己的bounds的

  • self.view.insetsLayoutMarginsFromSafeArea

如果你不想让safeAreaInsets影响你的视图布局,则可以将insetsLayoutMarginsFromSafeArea设置为NO,所有的视图布局将会忽略safeAreaInsets这个属性了。

要注意的是,insetsLayoutMarginsFromSafeArea仅用于AutoLayout,即使该属性为NO,视图的safeAreaInsets还是一样有值,而且安全区域变更方法safeAreaInsetsDidChange一样被调用。

  • contentInsetAdjustmentBehavior

在iOS11 中, UIViewController的automaticallyAdjustsScrollViewInsets属性已经不再使用,我们需要使用UIScrollView的 contentInsetAdjustmentBehavior 属性来替代它.

UIScrollViewContentInsetAdjustmentBehavior 是一个枚举类型,值有以下几种:

automatic 和scrollableAxes一样,scrollView会自动计算和适应顶部和底部的内边距并且在scrollView 不可滚动时,也会设置内边距.
scrollableAxes 自动计算内边距.
never不计算内边距
always 根据safeAreaInsets 计算内边距

2. Safe Area 与 Layout Margins

一般在做 UI 设计,背景色或较不重要的內容可完整地延伸至屏幕边缘;主要的内容呈现区域 (例如 Table View) 会往内缩 (indent) 一层,称为「Safe Area」;而通常文字或是按钮等更加关键的物件,考虑到美观及操作性,會再内缩一层,称之为「Layout Margins

竖屏时的 Safe Area 可延伸至屏幕左右两侧,上部留 44pt 給 Status Bar;Layout Margins 通常左右再内缩 16pt。
横屏时的 Safe Area 左右两侧皆内缩 44pt;Layout Margins 通常左右再内缩 16pt。
Home Indicator

Home Indicator 为 iPhone X 屏幕下方的一个操控區域,外观是一条粗线 (手把),由屏幕底部往上滑动可返回主界面 (Home Screen),或进入多任务管理界面 (App Switcher)。

注意:该“粗线”不可自定义外观,系统会自动判断背景颜色,深色背景时显示浅色 Bar,浅色背景时则显示深色 Bar。

3. Edge Protection

如果你的 UI 带有由屏幕底部往上滑动 (Swipe) 的手势,可能会与系统的手势冲突,这时可告诉开发者该 UI界面需要启用「Edge Protection」。
启用时,Home Indicator 将会变得较为透明,并下降位置 (但还在),让全屏体验更为完整。当使用者第一次由下往上滑动时,此手势将保留给你的 App 使用,而不会触发 Home Indicator;当使用者在这时进行第二次滑动,才会触发。

注意:此选项将造成使用者不便,因此当真的有需要时再考虑启用

4. Auto-Hide

UI 中若是有影片播放等需要降低干扰的情况,需要完全隐藏 Home Indicator,可启用「Auto-Hide」选项,启用时,若是使用者数秒内沒有操纵行为,Home Indicator 将自动隐藏,直到使用者触碰界面才会再度出现。

注意:此选项将造成使用者困惑,因此當真的有需要时再考虑启用。

推荐:

坚持原创技术分享,您的支持将鼓励我继续创作!