IOS 多端适配
现在在开发 IOS 应用时,默认是保证可以同时在 iphone 和 ipad 上运行的。不过,这就会面临一些多屏适配性问题。
在 IOS 中写页面有两种方式,一种通过 code,直接在对应 viewController 中描述对应元素的特性即可(这种方式在大型项目中用的很多;另外一种是直接利用 storyboard,通过 UI 拖拽 加属性面板设置,来实现页面布局和设计。
其中在布局上比较重要的是 IOS 中的 constraint
概念,通过限制一个 view 在上下左右的位置 和 自身尺寸大小就可以实现布局定位的效果。
对比前端中 CSS 布局来说,可以算是简洁和高效了。也就是说,你不用再管啥 盒模型、浮动布局、margin 塌陷、inline-box 默认 padding 距离等奇怪的问题。
下文就主要介绍一下苹果体系下,如何做宽屏适配特性。
以前如果只是适配多个屏幕的 iphone 的话,实现很简单直接通过 SCREEN_WIDTH
全局宏直接怼。按照 iphone6 的 375px 宽度来进行尺寸适配。
self.leftCol.width = 20 * SCREEN_WIDTH
不过,苹果还提供了其他更多更丰富的适配工具:
* auto layout 多屏适配
* 类比 CSS 中 flex 布局的 StackView 适配
* 最新 iPad 上提供的 multitask(splitview) 适配
auto layout 多屏适配
Auto Layout 是 storyboard 里面的一个子属功能,用来进行多屏适配用的。它的主要功能是可以通过你设置的 constraints ,来动态设置 View 的 position 和 size ,达到动态适配的效果。
其中设置多屏的关键点,首先在于如何区分多屏。目前,IOS 提供了 trait
的环境变量,用来指明当前屏幕的横竖和比例关系。trait
是用来描述屏幕大小、横竖屏的一个概念集合。
还记得,在 Xcode 工具栏中,有一行指明了当前的机型和屏幕:
其中 C 代表 compact
;R 代表 regular
。这两个属性是用来描述屏幕短边和长边的特征。例如:
* wC hR : 本意是 width compact, height regular,那么对应就是 手机竖屏的模式
* wR hC: 本意是 width regular, height compact,那么对应就是 手机横屏的模式
* wR hR: 本意是 width regular, height regular,那么对应就是 iPad 模式
在实际代码中,你可以直接通过 traitCollection
去获取对应的 horizontalSizeClass
和 verticalSizeClass
属性,然后通过对比值来进行判断。
var isIpad: Bool {
return horizontalSizeClass == .regular && verticalSizeClass == .regular
}
var isIphoneLandscape: Bool {
return verticalSizeClass == .compact
}
var isIphonePortrait: Bool {
return horizontalSizeClass == .compact && verticalSizeClass == .regular
}
var isIphone: Bool {
return isIphoneLandscape || isIphonePortrait
}
当然,更直接的是通过 UIDevice.current.model
来直接获取机型、屏幕旋转方向之类的变量。
Auto Layout 提供了一种可视化的方式,来让你直接设置 constraints。首先点击 Vary for Traits
:
然后,针对当前屏幕适配添加对应 constraints。搞定之后,完成确认即可:
一般实践中,更直接的使用代码去描述:
if (isDeviceIpad()) {
mask.centerX = 1.0 * superview.centerX
mask.centerY = 1.0 * superview.centerY
mask.width = 0.5 * superview.width
mask.height = 0.5 * superview.height
return;
}
StackView 适配
苹果提供一个简便的自适应容器 StackView,有点类似 CSS 中的 flex 布局属性,你可以很容易构建一个水平或者垂直的流式布局。它最大的一个特点是会自动为里面的 UIView 构建布局约束。
UIStackView 拥有三个规则 分布方向、对齐规则、分布规则,优先指定 axis
属性,来定义布局轴的方向。这个属性的特点就是很适合用在 横竖屏切换上使用,按照 iphone 的 wRhC(横屏)、wChR(竖屏) 的 trait 设置不同的 constraint,可以得到响应式适配的效果:
- wRhC 横屏布局: UIStackView.axis = “horizontal”, Distribution = “Equal Spacing”
- wChR 竖屏布局:UIStackView.axis = “vertical”, Distribution = “Equal Spacing”
IOS multitask(splitview) 适配
IOS multitask 是 iPad 提供给 app 进行多窗口交互的一个特性,这个特性可以极大增加办公效率,不需要频繁切换 app 运行。当然,更多的时候,也是对宽屏下, app 运行的一个补充。
默认情况下,我们在 iPad 上默认打开的 app 叫做 primary app
,通过 splitView 加入的,称为 secondary apps
。 由于两个 app 都是全屏打开,所以,对于全屏下的某些权限来说,primary app 独有某些权限:
* 拥有状态栏的控制权
* (还有些权限不重要,就不说了
另外,splitView 主要针对的是 IOS 原生适配,如果想要嫁接到小程序或者 app 内应用去做的话,那可能就是 app 本身自己定义一套 splitView 规范。不过,ipad 的 splitView 规范还是很有参考性的。
整体分配的比例如下:
Landscape 分屏
Landscape 的分屏尺寸如下,将屏幕分成 3 份,只会存在 2:1 的比例,没有 1:1 等分尺寸。也就是说当有 A、B 两个 app 时,排布只会有:
* A = 1/3, B = 2/3
* B = 2/3, B = 1/3
而对于两个 app 默认的 trait 都是 wChR,也就是常规 iPhone 的交互比例大小。
Horizontal 分屏
当 iPad 处于横屏时,整体的宽度被拉长了,所以分屏的选择性就多了一个 等分, 1:1。现在 iPad 在横屏下的分屏就有 1:2 和 1:1 两种排列。同样,假设有两个 app, A、B,两者的排布方式就有:
- A = 1/3, B = 2/3
- A = 1/2, B = 1/2
- A = 2/3, B = 1/3
在非 iPad Pro上,两个 app 屏幕 trait 的表达如下:
* A = 1/3 (wChR), B = 2/3 (wRhR)
* A = 1/2 (wChR), B = 1/2 (wChR)
* A = 2/3 (wRhR), B = 1/3 (wChR)
但是,在 iPad Pro 上,等比排布时,会有区分:
* 非 iPad Pro
* A = 1/2 (wChR), B = 1/2 (wChR)
* iPad Pro:
* A = 1/2 (wRhR), B = 1/2 (wRhR)
前文了解了 IOS 生态下的多端适配,它主要有两个思路:一个是提供多种自适应组件,去实现多端适配的交互;另外一种是专门针对某个硬件设备屏幕,提出突破 app 层的交互,最有特点的就是 splitView。
这也可以带给我们很多启发,在小程序中如何做到最优的体验适配,以及能否带给开发者突破 小程序 层面的交互体验,这也是另外一个主要突破方向。
参考文献:
- Auto Layout Guide: Understanding Auto Layout
- Auto Layout Guide: 代码设置constraint
- UIDevice 获取机型
- UIStackView - UIKit | Apple Developer Documentation
- Use Multitasking on your iPad - Apple Support
- Adopting Multitasking Enhancements on iPad: Getting Oriented - https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/AdoptingMultitaskingOniPad/index.html