iOS的UIScene与多窗口

iPadOS 13开始支持多窗口。什么是多窗口?以系统自带的日历app为例:

日历app打开两个窗口

日历app可以打开多个窗口。但是多窗口并不是应用多开,虽然我们在多任务切换中可以看到貌似开了两个日历app,但它们只是日历app的两个窗口。

目前只有iPadOS支持多窗口,iOS并不支持多窗口。

多窗口的实现方式

为了实现多窗口,iPadOS 13引入了新的概念:scene(场景),每一个窗口就是一个scene。以前一个app只能存在一个key window,现在每个scene都有自己的key window。

如何使用scene

要使用scene,首先保证系统在iOS 13&iPadOS 13以上,然后对Xcode项目进行如下修改:

  1. Info.plist文件中添加Application Scene Manifest配置;
  2. 实现UIApplicationDelegate新增的管理scene生命周期的方法;
  3. 实现scene代理。

如果使用Xcode 11来创建新项目,会自带以上配置。如果是旧项目,就要手动添加以上配置了。

Application Scene Manifest

首先要在Info.plist文件里面添加Application Scene Manifest配置来让项目使用scene。

如果要让项目不使用scene,就要在Info.plist文件中删除Application Scene Manifest配置

Application Scene Manifest是一个字典,他有Enable Multiple Windows和Scene Configuration两个键:

Application Scene Manifest

Enable Multiple Windows是一个布尔值,标记该app是否支持多窗口。目前iOS是不支持多窗口的,只有iPadOS支持多窗口。如果你需要开发一个需要支持多窗口的iPad应用,那就需要设置为YES,否则就设置为NO就可以了。

就算不需要多窗口功能,也不妨使用scene来管理窗口,因为现在使用scene是Xcode的默认配置了。

Scene Configuration是一个字典,用来添加scene的配置信息:

Scene Configuration

有两种角色(role)的scene:External Display Session RoleApplication Session RoleExternal Display Session Role与使用外部显示设备有关,用的较少。一般配置Application Session Role就可以了。

可配置的scene信息有四个:Class NameConfiguration NameDelegate Class NameStoryboard Name,其中Configuration NameDelegate Class Name是必选的:

  1. Class Name。scene的类名,必须是UIScene的子类。如果是Application Session Role,必须是UIWindowScene的子类;
  2. Configuration Name。为这个配置起一个名字,必选值;
  3. Delegate Class Name。scene代理的类名,必须是实现UISceneDelegate的类,如果是Application Session Role,必须是实现UIWindowSceneDelegate的类。必选值;
  4. Storyboard Name。scene的窗口内容来源的Storyboard的名字,可选值。

scene对象和scene代理都不允许手动创建,只能在Info.plist中指定,然后由UIKit自动创建。

UIApplicationDelegate中管理scene生命周期的方法

UIApplicationDelegate为了支持scene新增两个方法:

#pragma mark -- UIScene Support --
// Called when the UIKit is about to create & vend a new UIScene instance to the application.
// The application delegate may modify the provided UISceneConfiguration within this method.
// If the UISceneConfiguration instance returned from this method does not have a systemType which matches the connectingSession's, UIKit will assert
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0));

// Called when the system, due to a user interaction or a request from the application itself, removes one or more representation from the -[UIApplication openSessions] set
// If sessions are discarded while the application is not running, this method is called shortly after the applications next launch.
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions API_AVAILABLE(ios(13.0));

其中-[application:configurationForConnectingSceneSession:options:]很重要,因为需要通过它获取scene的配置信息来创建新的scene:

- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
    UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
    return config;
}

-[UISceneConfiguration initWithName:sessionRole:]只能获取Info.plist中Application Scene Manifest已经填写的Scene Configure信息。

scene代理

scene代理,一个实现UISceneDelegate的类。如果是Application Session Role的scene,那就是一个实现UIWindowSceneDelegate的类。scene代理只能在Info.plist中的Scene Configuration指定,然后被UIKit自动创建。

对于Application Session Role的scene,需要创建root window。如果已经在Info.plist中的Scene Configuration指定了Storyboard Name,那么root window会自动从Storyboard中创建。如果没有指定Storyboard Name,那么就需要在-[UIWindowSceneDelegate scene:willConnectToSession:options:]中手动创建root window。

你可能感兴趣的:(iOS的UIScene与多窗口)