适配的过程有点蛋疼,之后却越看越顺眼。
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
描述的区域也是跟自身一样大。所以要正确获取这两个属性的值,需要注意这两个值改变的时机。由于我们适配时,使用了简单粗暴的方法,这里不展开说明,具体细节可以参考这里。
当UIView
不在视图层级或者屏幕上的时候,safeAreaInsets = UIEdgeInsetsZero
,safeAreaLayoutGuide
描述的区域也是跟自身一样大。所以要正确获取这两个属性的值,需要注意这两个值改变的时机。由于我们适配时,使用了简单粗暴的方法,这里不展开说明,具体细节可以参考这里。
网易100分目前的用户界面布局现状
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
图片集合,网易100分目前使用的方式,在这个图片合集中添加一张1125px × 2436px
大小,@3x
的图片即可,命名无所谓;.plist
文件中进行配置。
由于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
。scrollVIew
的底部缩进引起的。另外,涉及到H5
内容的适配,以及页面底部存在悬浮视图的情况,这个就需要Web
端同事配合了。具体可参考这里
本文来自网易实践者社区,经作者吴丽君授权发布。