iOS开发 iPhone X 适配及 safeArea 引起的一
苹果公司于2017年9月13日凌晨发布了两款新的手机—— iPhon 8与iPhone X,作为全新的屏幕样式 iPhone X 的适配问题也成了大家都很关注的一个问题。
以下通过官方文档、项目中出现的问题、网上的资料来谈谈 iPhone X 的适配
一、官方文档说明
布局
1、在 iPhone X 上预览你的应用。你可以 Simulator(Xcode 附属应用 )来预览你的应用。请注意检查应用元素是否被屏幕切割、布局是否正常等。对于一些新特性,比如广色域显示,使用实体设备才能起到最好的预览效果。
2、为了更好的提供全屏使用体验。 确保背景能够延伸到屏幕边缘,垂直滚动布局,如表单或集合页需一直延续至屏幕底部。(亲测使用系统提供的标准组件没有问题)
3、插入必要内容以防止被裁切。一般来说,内容应该是居中对称的,这样在任何方向上都能获得比较好的观感,也不会被屏幕圆角、传感器区域和主屏幕支持器所影响。为了保证最佳效果,请使用系统提供的标准控件和响应式布局来构建您的页面。所有的应用都应该遵循 UIKit 定义的安全区域和布局边距,这些区域可以根据设备的上下文进行适当的填充。同时,安全区可以防止你的内容覆盖状态栏、导航栏、工具栏和标签栏。
4、注意状态栏的高度。iPhone X 的状态栏比其他 iPhone 上要更高一些。如果您的应用元素尺寸是根据状态栏高度来判断,或是元素位置处于状态栏下方,则必须更新您的应用,请跟据用户的设备来动态定位内容。请注意,当后台任务(如录音和位置跟踪)处于活动状态时,iPhone X上的状态栏不会改变高度。
5、如果您的应用目前是隐藏状态栏,请根据 iPhone X 屏幕特点重新考虑。iPhone X 的屏幕比 4.7 英寸 iPhone 的屏幕高很多,省去状态栏占据的内容区域可能并不会得到很好的利用。状态栏还展示了人们觉得有用的一些信息,请思考当你将它隐藏时换来的价值要高于显示。
6、在重复使用现有图稿时,请注意长宽比差异。iPhone X 与常规 iPhone 的屏幕长宽比不同,因此,全屏的 4.7 寸屏图像在 iPhone X 上会出现裁切或适配宽度显示。同理 iPhone X 的图片在 4.7 寸屏上也会出现此情况。所以,重要的视觉稿请根据设备型号做相应的调整。
7、避免将可交互控件放在屏幕底部和角落。屏幕底部可以通过手势进入主屏幕和多任务页面,这些手势可能会覆盖您在此区域中实现的自定义手势。屏幕角落可能无法让人们舒适地触达。
8、不要遮盖或引导关注屏幕新特性的关键位置。不要使用放置黑色栏在屏幕上下区域等方式来试图隐藏设备的圆角、传感器区域和主页指示器,也不要使用类似括号、轮廓、形状和教学文案等视觉元素来引导用户关注这些区域。
9、允许自动隐藏回到主屏幕指示器。当自动隐藏开启时,用户几秒钟不触碰屏幕指示器便会渐隐消失。用户触碰屏幕后指示器再次显示。此特性只能用于沉浸式预览样式,比如视频播放或幻灯片样式。
10、在横屏状态下官方给出的错误的设计样式和正确的设计样式
二、****iPhone X 屏幕变化总结
1、屏幕尺寸
5.15 英寸 458 ppi(ppi : 每英寸所拥有的像素(pixel)数目)
1125px × 2436px(75pt × 812pt @3x)
为了更好的突出 iPhone X 的屏幕显示效果,请使用 3 倍图
2、iPhone 7 和 iPhone X 对比:
如下图所示,iPhone 7 设备渲染后分辨率为 750 x 1334,逻辑分辨率只有 375 x 667。iPhone X 设备渲染后分辨率为 1125 x 2436,逻辑分辨率是为 375 x 812。可以看出显示区域宽度是相同的,但是高度多了 145pt
3、顶部多出传感器区域(俗称刘海),底部的实体 home 键消失,屏幕下方多出返回主页指示器(网上有称之为 homeBar 的,官方没有明确命名,为了方便表达,以下内容称之为 homeBar)屏幕四个角变成大圆角。官方文档上表明:在你为 iPhone X 设计界面时,请必须保证所有设计内容不能被屏幕圆角、上方传感器区域、下方返回主页指示器所遮挡。
屏幕快照 2017-10-11 下午3.49.28.png4、statusBar 的高度在 iPhone X 上变成了 44,其他设备都是 20。对于开发者来说,项目中隐藏导航栏,偏移量按照原来的 20 固定值来使用的,在屏幕上出现偏移。(对于 App 混合开发的项目,iOS 开发在开发中使用动态获取的值进行计算,前端开发的同学适配的时候可以通过获取手机型号来赋值)
屏幕快照 2017-10-10 下午5.33.30.png5、tabBar 的高度在 iPhone X 上变成了 83,其他设备是 49,多出 34,多出的部分是给 homeBar 流出控件,可以算出 homeBar 的高度为 34。
屏幕快照 2017-10-10 下午5.29.46.png三、适配**** iPhone X****的新特性
1、颜色
iPhone X 屏幕支持 P3 色彩空间,这意味着它将可以显示更多的色彩,比 sRGB 要更加艳丽。
使用广色域来提高视觉体验。使用了广色域的图片和视频会更加生动,使用广色域的数据图表和状态指示器会更加有冲击力。更多信息请查看「色彩管理」。
2、手势
iPhone X 使用屏幕边缘手势来访问主屏幕、应用切换、通知中心和控制用心。
避免干扰到系统级别的屏幕边缘手势。人们使用这些手势来使用所有应用,在极少数情况下,像游戏这样的沉浸式应用程序可能需要自定义的屏幕边缘手势。优先于系统的手势:第一次滑动会调用自定义手势,而第二次滑动则会调用系统手势。这种自定义行为(称为边缘保护)应该谨慎使用,因为它使得用户难以访问系统级的操作。更多信息请查看「手势」。
3、Face ID
iPhone X 支持 Face ID 进行身份验证。如果您的应用程序与 Apple Pay 或其他系统身份验证功能集成,请勿在 iPhone X 上引用 Touch ID。同样,请不要在支持 Touch ID 的设备上引用Face ID。更多信息请查看「验证」。
4、键盘功能
在 iPhone X 上,Emoji、语言切换和语音识别按钮会自动显示在键盘的下方(即使使用自定义键盘)。 您的应用程序不能影响这些按钮,为了避免造成困扰,请不要在键盘中重复定义这些按钮。
四、对于原有的项目,适配**** iPhone X ****可能会遇到的问题
1、App 页面没有完全充满屏幕
原因:
UIScreen的初始化是根据我们进入的第一个页面去进行参数化的
解决方式:
补上1125 x 2436的图或采用 LaunchScreen.xib 或者 LaunchScreen.storyboard 进行配置启动图
2、下拉刷新被头部刘海遮盖
原因:
头部刘海遮盖住了刷新控件
解决:
增加刷新控件的高度
3、个人中心界面头部导航栏问题
原因:
没有使用系统的导航栏,自定义的导航栏导致高度增大
解决方式:
动态获取导航栏高度作为自定义的导航栏高度
4、底部的按钮和 homeBar 重合
原因:
status 的高度改变,造成按钮和 Home 键重合
解决:
动态计算 frame 的值
(欢迎补充)
五、关于**** iOS11 ****新增新特性**** safeArea ****对项目造成的影响
在iOS11设备上运行出现最多问题应该就是 tableview 莫名奇妙的偏移 20pt 或者 64pt,原因就是iOS11弃用了 automaticallyAdjustsScrollViewInsets 属性,新增了 UIScrollView 的 contentInsetAdjustmentBehavior 属性,根本原因就是 iOS11 新引入的 safeArea 引起(个人认为这是 iPhone X 屏幕的大浮动变动引起的,为了 view 不被 statusBar、navigationBar、tabBar 遮住,更好的适配 iPhone X)
什么是安全区域呢?
如下图,蓝色区域为安全区域。系统认为 statusBar、navigationBar、tabBar 之外的区域为安全区域,对于 UIScrollView、UITableView、UICollectionView,系统会自动给他添加一个内边距,造成偏移。即使把 navigationBar 设为透明,系统也认为安全区域是从 navigationbar 的 bottom 开始的。
比如:当你的APP中使用的是自定义的 navigationbar,隐藏掉系统的navigationbar,并且 tableView 的 frame 为 (0,0,SCREEN_WIDTH, SCREEN_HEIGHT) 开始,那么系统会自动调整SafeAreaInsets值为 (STATUS_BAR_HEIGHT,0,0,0),如果使用了系统的 navigationbar,那么 SafeAreaInsets 值为 (64,0,0,0),如果也使用了系统的 tabbar,那么 SafeAreaInsets 值为 (STATUS_BAR_HEIGHT + NAVI_BAR_HEIGHT, 0, TAB_BAR_HEIGHT, 0)。(SCREEN_WIDTH 表示屏幕宽,SCREEN_HEIGHT 表示屏幕高,STATUS_BAR_HEIGHT 表示状态栏高度,NAVI_BAR_HEIGHT 表示导航栏高度,TAB_BAR_HEIGHT 表示底部选项卡高度)
官方定义:安全区域定义了view中可视区域的部分,保证不被系统的状态栏、或父视图提供的 view 如导航栏覆盖。
当项目中出现莫名偏移的情况,可参考的解决方法:
1、根据取代 automaticallyAdjustsScrollViewInsets 属性的 contentInsetAdjustmentBehavior 属性
if (@available(iOS 11.0, *)) {
self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
// 设置内边距
self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
// 设置滚动条的内边距
self.webView.scrollView.scrollIndicatorInsets = self.webView.scrollView.contentInset;
} else {
self.automaticallyAdjustsScrollViewInsets = false;
}
2、根据 iOS11 UIScrollView 新增的两个属性:adjustContentInset 和 contentInsetAdjustmentBehavior
if (@available(iOS 11.0, *)) {
self.additionalSafeAreaInsets = UIEdgeInsetsMake(-STATUS_BAR_HEIGHT, 0, 0, 0);
// 如果使用了 navigationBar,又把它隐藏的情况, additionalSafeAreaInsets 要找到使它偏移的 Controller
// self.navigationController.additionalSafeAreaInsets = UIEdgeInsetsMake(--NAVI_BAR_HEIGHT, 0, 0, 0);
} else {
self.automaticallyAdjustsScrollViewInsets = false;
}
关于scrollView在iOS11新增的两个属性 adjustContentInset 和 contentInsetAdjustmentBehavior:
adjustContentInset 表示 contentView.frame.origin 偏移了 scrollview.frame.origin 多少;
是系统计算得来的,计算方式由 contentInsetAdjustmentBehavior 决定。
有以下几种计算方式:
- UIScrollViewContentInsetAdjustmentAutomatic: 如果 scrollview 在一个automaticallyAdjustsScrollViewInsets = 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 值的影响。