个人感觉UISplitViewController
是比较鸡肋的东西,开发中自定义splitViewController
的时候比较常见。
介绍
UISplitViewController
类是一个容器视图控制器,它显示一个master-detail
界面(主界面、详细界面)。在master-detail
界面中,主视图控制器(master
)的变化会驱动辅助视图控制器(detail
)变化。 两个视图控制器(master
控制器、detail
控制器)的排列是可以控制的, 他们可以同时显示或者一次只显示一个。UISplitViewController
在iOS3.2的时候就有了,只不过iOS8才开始支持iPhone(比如在iPhone6 plus上显示视图和iPad很相似了)。
Overview
在构建应用程序的用户界面时,splitViewController
通常是应用程序窗口(window)的根视图控制器。splitViewController
没有明显的外观,它的外观基本上是由它的子视图控制器(master、detail控制器)决定的。 你可以以Interface Builder
的方式或者代码的方式构建该控制器。
Note
你不能把splitViewController
push到navigationController
的栈中
尽管在一些容器视图控制器中,把splitViewController
当做子控制器这个操作是可行的,但是大多数情况不允许这么做。再次声明,splitViewController
通常配置为window的root控制器。 有关实现界面的方法的提示和指导,请参阅iOS Human Interface Guidelines。
splitViewController
基于可用空间确定其子视图控制器的排列:
在水平规则的环境中,splitViewController
尽可能并排地呈现其视图控制器(同时并排地显示master、detail控制器)。
在水平紧凑的环境中,splitViewController
的行为更像导航控制器,最初显示主视图控制器,并根据需要push
或pop
第二个控制器。
当显示在屏幕上时,splitViewController
使用其"代理对象"(Delegation object)来管理其子视图控制器的显示。具体参考此处:UISplitViewControllerDelegate
Configuring the Appearance of the Split View Interface
splitViewController显示的视图配置由当前显示模式(displayMode
)决定。 配置displayMode需要用到preferredDisplayMode
属性。
分割视图控制器尽力尊重您指定的显示模式,但由于空间限制,可能无法视觉上适应该模式。 例如,分割视图控制器不能在水平紧凑的环境中并排显示其子视图控制器。
下面列出了可用的显示模式,并描述了视图控制器如何布置在屏幕上。 该表还列出了用于请求指定显示模式的常量。
-
Side-by-side
同时显示全部控制器。主视图控制器显示在左侧,通常比次视图控制器更窄。可以使用preferredPrimaryColumnWidthFraction属性来控制宽度.
当isCollapsed
属性为true的时候,这个模式不会显示。在折叠的界面(collapsed interface)时,一次只能看到一个试图控制器。
这个模式由枚举中allVisible
表示。
-
Hidden:
次视图控制器显示在屏幕上,主视图控制器处于关闭屏幕。
要显示主视图控制器,您必须以模态显示(present it modally)或更改显示模式(change the display mode)。
该模式由枚举中的primaryHidden
表示。
-
Overlay
次视图控制器在屏幕上,主视图控制器分层在其上。 在此模式下,主视图控制器部分地遮挡了次视图控制器(如下图:右侧的控制器一部分被遮挡了)。
此模式由primaryOverlay
表示。
当设置完preferredDisplayMode
后,splitViewController会自动更新,并在displayMode
属性中反映实际的显示模式。
您可以随时更改首选显示模式,这样做会导致splitViewController相应地进行自我调整 。
分割视图控制器还安装内置手势识别器,让用户使用滑动来更改显示模式。您可以通过将presentsWithGesture
属性设置为false来抑制此手势识别器。
displayModeButtonItem
方法返回一个特殊的barButtonItem
,用于改变displayMode
,你可以将其包含在应用程序的用户界面中。
你需要做的是将这个barButtonItem
添加到界面中相应的navigation bar
或toolbar
。
当它点击被的时候,按钮会向splitViewController发送一个消息,告诉它改变当前的displayMode
。
关于改变的结果取决于代理方法中的targetDisplayModeForAction(in:)
方法(ps: Objctve-C中对应targetDisplayModeForActionInSplitViewController:
)。次方法缺省值的为Automatic
- (UISplitViewControllerDisplayMode)targetDisplayModeForActionInSplitViewController:(UISplitViewController *)svc {
if (self.displayMode == UISplitViewControllerDisplayModePrimaryHidden) {
return UISplitViewControllerDisplayModeAllVisible;
}else if (self.displayMode == UISplitViewControllerDisplayModeAllVisible){
return UISplitViewControllerDisplayModePrimaryHidden;
}else{
return UISplitViewControllerDisplayModePrimaryHidden;
}
}
上述代理如果设置返回的是UISplitViewControllerDisplayModeAutomatic
或者干脆没实现这个代理方法,视图控制器会根据当前屏幕大小选择合适的模式。 例如,在竖屏的iPad上,控制器在hidden和overlay模式之间切换。
切换模式也可以通过手势来进行,手势也可以通过代理方法来确定要使用的显示模式。
Changing Child View Controllers in a Split View Interface(改变子视图控制器)
当设计一个splitViewController的时候,当然如果主视图和辅助视图都不改变是最好的。
常见的技术是在主视图和辅助视图都是导航控制器(navigationController)控制的,然后可以根据实际的需要进行控制器的push
或者pop
操作.
如果需要更改主视图控制器或辅助视图控制器,建议您使用show(_:sender:)
和showDetailViewController(_:sender:)
方法。使用这些方法(而不是直接修改controllers
属性)使分割视图控制器以最适合当前显示模式和size class的方式呈现指定的视图控制器。
splitViewController知道如何以更直观的方式调整界面。它甚至可以与其他容器视图控制器(如导航控制器)一起使用来呈现视图控制器。举个有点特殊的例子,在比较紧凑(compact
)的环境中(比如iPhone 6plus的横屏状态),开始显示的控制器A(辅助视图)是一个导航控制器。这时候调用showDetailViewController(_:sender:)
方法并不会替换掉视图控制器A。相反,视图控制器A将目标控制器push到其导航堆栈。
Collapsing and Expanding the Split View Interface
splitViewController进行展开和收齐的时候,它的size class
在水平方向的regular
和compact
间切换。 在切换过程中,splitViewController会改变子视图控制器的显示方式.
当从水平方向regular
转换到compact
时,splitViewController”收起“后显示一个控制器。
当从水平方向compact
转换到regular
时,splitViewController会根据设定的displayMode
屏幕”展开“显示一个或多个控制器.
收起 (collapsing process)
当界面转换到“收起"时,分割视图控制器与其代理一起管理转换。在”收起“结束时,splitViewController通常只显示主视图控制器了。
你可以在代理中实现primaryViewController(forCollapsing:)
方法来变此行为。您可以使用该方法来指定次视图控制器或完全不同的视图控制器 - 也许那个控制器更适合在水平方向compact
的环境中显示。
如果相对控制器和视图层次进行额外调整,你可以在代理中实现splitViewController(_:collapseSecondary:onto:)
方法。
展开 (expansion process)
展开是收起的相反的过程。这一过程会询问delegate哪个控制器将成为主视图控制器(primary view controller)并且提供给delegate机会去执行transition变换。
如果你实现了"收起"的代理方法,那么同样你也应该为"展开"实现primaryViewController(forExpanding:)
和splitViewController(_:separateSecondaryFrom:)
方法。
如果没实现“收起”和“展开”的任何代理方法,那也没关系。splitViewController提供了收起/展开的缺省值。
关于收起(collapse)、展开(expand)的更多信息,请查看UISplitViewControllerDelegate.
Message Forwarding to Its Child View Controllers
splitViewController对window和子控制器(child view controllers)进行了协调。 因此所有到子控制的所有消息都会流经splitViewController.
这通常可以预期,消息的流程应该比较直观。 例如,仅当相应的子视图控制器实际出现在屏幕上时才会发送查看外观显示或消失的消息。
State Preservation
在iOS6或者更高版本上,如果你给定了splitViewController的restorationIdentifier属性值。 那么它将会保存具有有效恢复标识符(valid restoration identifier)的所有子控制器。
在程序下一次启动时,splitViewController将会回复到之前的状态。splitViewController的子视图控制器可以使用相同的恢复标识符。splitViewController自动存储附加信息,以确保每个子控制器的恢复路径是唯一的。
有关状态保存和恢复的工作原理的更多信息,请参阅App Programming Guide for iOS。
参考内容
https://developer.apple.com/reference/uikit/uisplitviewcontroller
http://nshipster.cn/uisplitviewcontroller/