多任务(multitasking)算是iOS9中最引人瞩目的核心新特性了,之前越狱版用户就用过类似的插件,微软的 苏菲 (Windows Surface)系列也有分屏多任务的特性,可以让用户可以同时运行2个或者多个App。iOS 9 中的多任务目前支持三种表现形式:临时出现和交互的滑动覆盖 (Slide Over);真正的分屏同时操作两个 App 的分割视图 (Split View);以及在其他 App 中可以进行视频播放的画中画 (Picture in Picture) 模式。
在官网关于多任务的开发文档中,Apple有明确指出:绝大部分 App 都应当适配 Slide Over 和 Split View。且最新的XCode 7 Beta版新创建的Project,默认就是支持多任务滴~当然如果你的App只需要全屏体验(例如游戏类,或者实在不想维护适配更新老项目的代码 J),你可以在Info.plist 中添加 UIRequiresFullScreen 项并将其设为YES,从而禁止分屏功能。就是这么简单~~
图1 App 设置示意图
目前只有支持iOS 9的部分设备可以使用多任务功能,其中支持分割视图 (Split View)的设备只有目前性能最好的iPad Air 2 (& 之后的新发布设备)。而支持支持滑动覆盖和画中画两种模式的设备则较多,例如iPad mini 2、iPad mini 3 以及 iPad Air、iPad Air 2等。这个也比较好理解,毕竟是移动设备,还是得考虑性能及用户体验。这里我们暂时不讲画中画模式(其实是项目中暂时没用到~)
Slide Over功能默认是被激活的,用户可通过该功能调出屏幕右侧的悬浮视图(在从右到左的语言环境下位于屏幕的左侧),从而查看次要应用程序并与其进行交互。如果不能滑出悬浮视图,请确认”设置->通用->多任务->允许多个应用”选项是否开启。
图2 Setting 设置示意图
在Slide Over区域之外靠近屏幕中间的位置有一个按钮,拖拽这个按钮就会进入分割视图 (Split View)模式。在Split View模式中,会呈现为两个并行的应用,用户可以查看、调整其大小,并与其进行交互。左侧的App是主要App,右侧的是次要App,将次要App拖动到最左边时,次要App变成主要App,而原先的主要App退出前台。目前 Split View支持的分屏比例有三个,分别为 1/2、1/3、2/3。妾以为,Split View 才是真正的多任务,至少是2个可以并行运行&操作的App;而Slide Over则看上去有点假,是一个App覆盖在另外一个App上面的。
图3 分割视图模式示意图
图4 分割视图模式示意图
好,现在再回到扣腚过程中~~
如果是用XCode 7新创建的项目,那么恭喜你,按照Apple推荐的标准流程开始走吧,你会感恩的。如果需要做老项目升级适配的,并且Code中的坐标定位是写死的,那么请准备好湿巾纸,可以一边抹吐沫星子一边抹泪一边适配了,一想到我们的PDF Reader系列要做适配,就觉得心塞··,38度的暖夏也是寒冷的说·好,如果要激活多任务,你需要
- 配置一个启动XIB作为启动页面,例如LaunchScreen.xib,配置给UILaunchStoryboardName就好了
- App支持所有方向(UISupportedInterfaceOrientations),UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft,统统都配置上去吧
- 尽情使用 自动布局(Auto Layout)吧
- 尽情使用 Adaptive UI吧,像 Size Class,Dynamic Type神马的,统统来吧
Info.plist列子:
<key>UILaunchStoryboardName</key>
<string> LaunchScreen </string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
这里的Size Class有个部分需要注意,此前iPad的水平和垂直Size Classes总是“Regular”。随着分屏出现,这些会发生改变。下图显示了你的App会遇到用户操作iPad屏幕后不同的Size Classes。从图中可以看出在垂直方向上无论横竖屏都是Regular布局,在水平方向上有Regular布局和Compact布局两种;因此在做界面适配时,要处理的Size Classes有w:Regular h: Regular和w:Compact h:Regular两种。
图5 视图分割布局种类示意图
iOS 9分屏功能最麻烦的地方就是界面的自适应,需要使用Auto Layout和Size Classes来处理。如果你的App完全做到自适应UI,那么实现分屏功能几乎不用做太多处理,用Xcode7重新编译下就OK。我写了一个iOS9分屏Demo,用XIB和纯代码两种方式实现自适应UI,大家可以参考下。至于项目开发用XIB还是用纯代码,各有利弊,看大家个人习惯及项目情况来选择了。我比较赞成唐巧在这篇文章中说到的做法。由于我们公司项目大多都是协同开发,考虑到代码版本管理冲突的概率比较大以及代码复用问题,我自己项目中很少用到XIB / Storyboard。
这里大概介绍下XIB的实现方式,先在XIB界面下方选择w:Regular h: Regular这种SizeClass,然后通过拖拽控件以及为这些控件添加合适约束和布局;接着选择w:Compact h:Regular这种SizeClass,添加新的约束和布局调整界面,这样就实现了界面的自适应,效果如下图。这里不详述SizeClass和AutoLayout处理方式,如果你对SizeClass和AutoLayout不太了解,可以看下这篇文章。
图6 Demo App界面设计
图7 Demo App界面设计
用代码处理界面自适应的话,我们可以根据当前的UIView 的 traitCollection 属性来获取当前的SizeClass类型,然后根据SizeClass类型来做UI布局。并且可以在UIViewController的 -willTransitionToTraitCollection:withTransitionCoordinator: 和 -viewWillTransitionToSize:withTransitionCoordinator: 被调用时获取新的SizeClass类型,然后调整为新的UI布局。UI布局主要是处理Views之间的约束关系来实现AutoLayout,若使用Apple原生的API来写Views的约束条件,代码量会比较多,界面布局的代码也会有些杂乱;你可以借助第三方库来写AutoLayout代码,这样可以减少很多代码,例如Masonry,PureLayout等。本文Demo中布局的代码大致如下:
- (void)willTransitionToTraitCollection:(nonnull UITraitCollection *)newCollection withTransitionCoordinator:(nonnull id<UIViewControllerTransitionCoordinator>)coordinator {
if (UIUserInterfaceSizeClassCompact == newCollection.horizontalSizeClass) {
[self layoutAllSubviews:YES];
} else {
[self layoutAllSubviews:NO];
}
}
- (void) layoutAllSubviews:(BOOL)isCompactLayout {
int padding = 20;
if (isCompactLayout) {
[self.greenView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).offset(padding);
}];
} else {
[self.greenView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.greaterThanOrEqualTo(superview.mas_top).offset(padding);
}];
}
}
本文Demo运行的效果如下,在w:Compact h:Regular这种SizeClass情况下显示3排,每排一个View,在w: Regularh:Regular这种SizeClass情况下显示2排,第一排显示两个Views
图8 Demo视图分割示意图
图9 Demo视图分割示意图
几个小细节
- UIScreen.bounds 和 UIWindow.bounds 的尺寸大小不再相同,UIWindow可能只有屏幕的 1/2 或 1/3了
- Size Class 是会发生变化的,文章上面有提到。在开发时需要考虑用户体验部分(如果没有设计师的,就自动忽略吧··),包括 适配屏幕大小的UI设计和尺寸变化的切换效果。可以试试transitionCoordinator 的 -animateAlongsideTransition: 来进行布局动画,让切换更加自然。
- 如果你的App不使用Slide Over和Split View功能,那么你的App也不能出现在Slide Over 区域中,尽管你的App 运行在多任务环境中。
- 需要考虑App支持的版本,如果还需要支持 iOS 6 神马的,做好哭得准备吧,版本判断之类是少不了的
- 留意合理分配使用内存,监听 Memory Warning以便于释放 Cache 和不必要的 View Controller,避免循环引用等等
- 即使是Split View模式,App也得继续在各自的沙河(Sandbox)中运行,要实现真正意义上的App间互动,还有很长路要走~~
参考链接
https://www.hackingwithswift.com/read/31/5/ipad-multitasking-in-ios-9
http://www.cocoachina.com/ios/20150714/12555.html
http://onevcat.com/2014/07/ios-ui-unique/
http://blog.devtang.com/blog/2015/03/22/ios-dev-controversy-2/
https://github.com/SnapKit/Masonry