●●●
适配前的准备
拥抱iPhone X的变化
开始适配前,先回顾下,iPhone X相比之前的iPhone设备,带来了哪些不一样的特性:
iPhone X的屏幕尺寸
iPhone X的宽度同iPhone 6/6s/7/8,但高度多出来145pt,垂直方向可以承载更多内容。对于大多数用ScrollView展示内容的页面来说,这个尺寸的变化对布局影响不大,但对一些内容固定,布局需要强依赖设备尺寸和比例的页面,就需要留意一下,例如整张图片铺满屏幕的页面、启动引导页面、功能引导蒙层。
这类页面适配时,要注意图片缩放比例要合理,内容要撑满屏幕,不要四周留空白。
状态栏和导航栏
iPhone X的刘海,让statusBar变为由原来的20pt变为44pt,导航栏高度默认情况下仍然是44pt,不过iOS 11中新增了一种大标题的导航栏样式,如果设置了prefersLargeTitles = YES,则高度变为96pt。所以在iPhone X上,状态栏加导航栏(默认)高度是88pt,而不是之前的64pt,如果之前有一些隐藏导航栏,或者使用自定义导航栏的页面,都要全部走查一遍。
安全区域
iOS 11中新增了Safe Area的概念,它描述了视图不被其他内容遮挡的区域,避开了诸如导航栏,TabBar之类有可能挡住view的视图。iPhone X上默认的根视图的安全区域如下图:
关于安全区域的适配有几点要注意:
a. 圆角及传感器部分避免用户交互; b. 避免干扰底部Home Indicator,要让这部分清晰可见; c. 避免干扰系统边缘手势(实在有需求的话,可以开启边缘保护)
Safe Area可以有两种方式来获取:safeAreaInsets和safeAreaLayoutGuide。safeAreaInsets属性反映了一个view距离该view的安全区域的边距。对于一个UIViewController的根视图而言,safeAreaInsets值包括了被statusbar和其他可视的bars覆盖的区域和其他通过additionalSafeAreaInsets自定义的insets值。而该视图层级上的其他view的additionalSafeAreaInsets表示了该视图在父视图范围内的部分被覆盖的区域;
当UIView不在视图层级或者屏幕上的时候,safeAreaInsets = UIEdgeInsetsZero,safeAreaLayoutGuide描述的区域也是跟自身一样大。所以要正确获取这两个属性的值,需要注意这两个值改变的时机。由于我们适配时,使用了简单粗暴的方法,这里不展开说明。
目前的用户界面局现状
最低支持系统版本iOS 8.0,无法使用Safe Area Layout Guides,对于旧的页面,以后也不打算使用Safe Area Layout Guides重新布局。
主要的页面内容都是以UIScrollView或其子类来承载的,iOS 11之前,UIViewController默认的automaticallyAdjustsScrollViewInsets = YES可以让页面内容正常显示,在iOS 11之后,这个属性虽然被废弃了,但UIScrollView新增的属性contentInsetAdjustmentBehavior(默认值是UIScrollViewContentInsetAdjustmentAutomatic)也可以确保内容正确显示。
布局时未使用过topLayoutGuide和bottomLayoutGuide,基本都是参照superview,所以没有向Safe Area Layout Guides转换的问题。
简单粗暴的宏
为了快速适配,这里定义了几个宏。虽然有人吐槽这种适配方式扩展性不好,以后万一出现了更多机型,状态栏高度不是44pt了怎么办?最好的方式是都根据安全区域来适配。不过我觉得,就算这情况真的出现了,到时候也避免不了新一轮的适配吧。
#define JYFUHeightNavBar 44
#define JYFUHeightSystemStatus (JY_IS_IPhoheX ? 44 : 20)
#define JYFUHeightTopBar (JYFUHeightNavBar + JYFUHeightSystemStatus) //status bar和nav bar高度
#define JYFUHeightBottomGap (JY_IS_IPhoheX ? 34 : 0)
#define JYFUHeightTabBar (49 + JYFUHeightBottomGap)
#define JYFULeftContentMargin (JY_IS_Protrait ? 0 : (JY_IS_LandScapeLeft ? JYFUHeightBottomGap : JYFUHeightSystemStatus)) //全屏时iphoneX内容左边距,用于假旋转
#define JYFURightContentMargin (JY_IS_Protrait ? 0 : (JY_IS_LandScapeLeft ? JYFUHeightSystemStatus : JYFUHeightBottomGap)) //全屏时iphoneX内容右边距,用于假旋转
●●●
开始适配
启动图
适配iPhone X的第一步就是要给它提供一张启动图,系统是根据是否设置了相应机型的启动图来判断该机型是否适配。
启动图设置有三种方式:
使用LauchScreen.xib,这是官方推荐的方式,是Xcode6/iOS8的加入的功能,Xcode7之后默认添加的是LauchScreen.storyboard;
使用静态LaunchImage图片集合,在这个图片合集中添加一张1125px × 2436px大小,@3x的图片即可,命名无所谓;
放在工程下的普通文件夹中,这种古老的方式就比较麻烦一点,对图片命名有要求,添加完之后需要在.plist文件中进行配置。
TopBar变化适配
由于iPhone X上状态栏高度的变化,导致页面顶部的一些布局异常,主要有两种场景:自定义导航栏或者没有导航栏的情况。
自定义导航栏
这部分页面的自定义导航栏高度是写死的64pt,要全部改为JYFUHeightTopBar,特别是有些复杂的页面,页面布局要依赖导航栏高度的,改的时候也要非常谨慎。
无导航栏
没有导航栏的页面,顶部内容通常会需要延伸至状态栏区域。如果内容是以UIScrollView承载,那我们需要修改
scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
以前这部分扩展区域高度是
20pt
,在iPhone X
上是44pt
,因此紧贴着状态栏下面的这块视图高度需要重新计算。由于这部分不是宽高等比的,多余的部分会被截掉,所以需要视觉出图时注意图片里内容的布局。另外还有一种情况,像下面这个页面,轮播图是可以点击的,但是延伸至状态栏的部分是无法响应用户操作。调试发现UIScrollView有个私有属性,effectiveSafeAreaInset,其值为{44, 0, 0, 0},这个inset.top的值刚好是状态栏的高度,即当前页面的安全区域与屏幕顶部的距离。
有交互功能的控件避开安全区域
非安全区域,可以平铺内容用作展示,但是不能存在可交互的控件。
竖屏:
在我们项目中,顶部按钮相对独立,只需要调整距离约束就可以,而且也不多。但底部控件落入非安全区域的情况就比较多了,一些页面底部带有类似工具栏的容器视图,还有大量的浮窗,自定义action sheet等。这些情况可能就不是拔高底部内容这么简单了(大多数情况,视觉会觉得不好看,底部内容会重新设计),这部分的适配工作量还是很可观的。
横屏:
主要是一些需要全屏显示的页面,例如播放器之类,播放器上一般来说有不少控件,都需要往中间缩进,收到安全区域内。
其他要注意的问题
iPhone X上,非必要的话,最好不要隐藏状态栏。
UTableView在横屏时,UITableViewCell的contentView会自动insert到safe area。
内嵌WebView的页面的适配,内容加载出来之前,底部可能会出现黑色一条,这是由于scrollVIew的底部缩进引起的。另外,涉及到H5内容的适配,以及页面底部存在悬浮视图的情况,这个就需要Web端同事配合了。
——【特别推荐】——
网易MCtalk泛娱乐产品峰会
——New娱乐 趣IP——
8大嘉宾有料:网易云音乐产品总监沈博文 美拍内容副总裁 才华 每日故宫主创 彦风 网易云信副总经理
陈丽…
8大话题有趣:大内容时代下的短视频、超级IP产品要如何养成、故宫文物遗产的数字化新生命探索...
戳【阅读原文】即可报名
↓↓↓