关于iPhone X 的适配
1.屏幕尺寸相关变化
- 高度增加了145pt,变成812pt.
- 屏幕圆角显示,注意至少留10pt边距。
- 状态栏高度由20pt变成44pt,留意这个距离就能避开“刘海”的尴尬,相应的导航栏以上变化64->88。
- 底部工具栏需要为home indicator留出34pt边距。
- 物理分辨率为1125px * 2436px.
2.横竖屏安全区对比
3.其他设备安全区域对比
4.应用设计
5.控件布局
更多可查看官方文档和视频Creating apps for iPhone X.
如何让APP适配?
APP启动样式适配
相信有一部分道友的APP在iPhone X上运行时并没有像想象中那样占满整个屏幕, 而是保持着原有的高度 在屏幕中心位置, 针对这个问题 目前经过实验得出可以通过以下方式使APP按照全屏模式运行:
- 通过
LaunchScreen.storyboard
方式启动 - 如果使用的是Assets中的LaunchImage, 在增加了iPhone X尺寸的图片配置后.
LaunchScreen.storyboard
方式不用多说, 这里说一下如何在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"
}
按照以上方式配置就完全解决了这个问题.
APP内部样式适配
iOS11为UIViewController
和UIView
增加了两个新的属性safeAreaInsets
和safeAreaLayoutGuide
, 通过这两个属性我们可以获得安全区域的范围, 通过上图可以很清楚的看到安全区域的范围, 我们要做的是让那些不能被遮挡的内容和控件在安全区域范围内显示, 注意!这句话非常重要.
safeAreaInsets
适用于手动计算.safeAreaLayoutGuide
适用于自动布局.
Frame布局方式适配示例
一般来说 可以通过在原有视图坐标计算时加入安全区域的范围值, 下面举个例子:
一个APP 它的NavigationBar使用的是自定义的UIView
, 并非UINavigationBar
, 这个自定义的UIView
的frame
属性为CGRectMake(0, 0, 375, 64)
.
这样的UIView
在其他设备上是没有问题的, 标准的导航栏尺寸, 但是如果运行在iPhone X上 你会发现看上去无比的别扭, 因为异形屏幕会造成部分显示内容的遮挡问题, 这时候就要用到安全区域这个概念来解决这一问题.
先说一说通常自定义导航栏的结构, 高度是为64
由44
高度的导航栏内容区域和20
高度的状态栏区域(电池条那部分 status bar)组成, 44
高度的导航栏内容区域用来显示导航栏上的控件, 如返回按钮 标题视图等等, 现在, 在iPhone X上, 原来的状态栏(status bar)高度不再考虑了, 取而代之的是安全区域顶部间距safeAreaInsets.top
, 我们将原有的结构改为 安全区域顶部距离屏幕的距离safeAreaInsets.top
+ 导航栏内容区域44
, 这样完成了一个自定义导航栏视图在iPhone X上的适配.
下面是适配前后的效果对比:
再来看一下适配后的自定义导航栏视图的UI结构
这只是举一个简单的例子, 因为不同的应用设计都是不同的, 但是适配的思路都是一样的, 还是那句话 我们要做的是让那些不能被遮挡的内容和控件在安全区域范围内显示, 在计算布局时 将安全区域这个新特性考虑进去, iPhone X的适配也不是难事.
说一下在代码中的安全区域的适配该如何去写:
iOS11 为UIViewController
和UIView
增加了一个新的方法 - (void)viewSafeAreaInsetsDidChange;
这个方法如名字一样 在安全区域改变后会被调用, 我们可以在需要适配的UIViewController
和UIView
中重写这个方法, 并且在这个方法中来根据safeAreaInsets
属性更新子视图控件的布局位置.
这里有一点要注意的是当UIViewController
调用- (void)viewDidLoad
时它的所有子视图的safeAreaInsets
属性都等于UIEdgeInsetsZero
, 也就是说在- (void)viewSafeAreaInsetsDidChange;
方法调用前 是无法通过当前视图控制器的子视图获取到safeAreaInsets
的, 不过获取当前window对象的safeAreaInsets
属性用来计算也是可以的, 但是不建议这么做, 一个视图控制器的子视图的处理当然要以它所在的控制器为准.
- (void)viewSafeAreaInsetsDidChange
在UIViewController
中第一次调用的时间是在- (void)viewWillAppear:(BOOL)animated
调用之后, 在- (void)viewWillLayoutSubviews
调用之前.
当然如果你要改变一个UIViewController
的safeAreaInsets
值, 可以通过设置addtionalSafeAreaInsets
属性来实现, 例如你要自定义一些特殊的样式时.
如果你改变了一个UIViewController
的safeAreaInsets
属性值, - (void)viewSafeAreaInsetsDidChange
也会被调用.
另外, 给道友们的分享一个获取某View安全区域范围的宏
#define VIEWSAFEAREAINSETS(view) ({UIEdgeInsets i; if(@available(iOS 11.0, *)) {i = view.safeAreaInsets;} else {i = UIEdgeInsetsZero;} i;})
使用起来比较简洁
VIEWSAFEAREAINSETS(view).left
VIEWSAFEAREAINSETS(self.view).right
AutoLayout布局方式示例
iOS11以前,我们布局时, 视图的 top
和 bottom
一般参照的是 Top Layout Guide
和 Bottom Layout Guide
.
iOS11以后, 那两个参照已经 deprecated
(过时)了, 而是被Safe Area
所取代.