UIViewController 的表现方式

来源:互联网 发布:360浏览器收藏夹 mac 编辑:程序博客网 时间:2024/06/10 18:55

http://www.onevcat.com/2014/07/ios-ui-unique/

UISplitViewController

在用 Regular 和 Compact 统一了 IB 界面设计之后,Apple 的工程师可能发现了一个让人两难的历史问题,这就是 UISplitViewController。一直做 iPhone 而没太涉及 iPad 的童鞋可能对着这个类不是很熟悉,因为它们是 iPad Only 的。iPad 推出时为了适应突然变大的屏幕,并且远离 "放大版 iTouch" 的诟病,Apple 为 iPad 专门设计了这个主从关系的 ViewControlle容器。事实也证明了这个设计在 iPad 上确实是被广泛使用,是非常成功的。

现在的问题是,如果我们只有一套 UI 画布的话,我们要怎么在这个单一的画布上处理和表现这个 iPad Only 的类呢?

答案是,让它在 iPhone 上也能用就行了。没错,现在你可以直接在 iPhone 上使用 SplitViewController 了。在 Regular 的宽度时,它保持原来的特性,在 DetailViewController 中显示内容,这是毫无疑问的。而在 Compact 中,我们第一想法就是以 push 的表现形式展示。在以前,我们可能需要写不少代码来处理这些事情,比如在 AppDelegate 中就在一开始判断设备是不是 iPad,然后为应用设定两套完全不同的导航:一套基于 UINavigationController,另一套基于 UISplitViewController。而现在我们只需要一套 UISplitViewController,并将它的 MasterViewController 设定为一个 navgationController 就可以轻松搞定所有情况了。

也许你会想,即使这样,我是不是还是需要判断设备是不是 iPad,或者现在的话是判断 Size Class 是不是 Compact,来决定是要做的到底是 navVC 的 push 还是改变 splitVC 的 viewControllers。其实不用,我们现在可以无痛地不加判断,直接用统一的方式来完成两种表现方式。这其中的奥妙在于我们不需要使用 (事实上 iOS 8 后 Apple 也不再提倡使用) UINavigationController 的 pushViewController:animated:方法了 (又一个老朋友要和我们说再见了)。其实虽然很常用,但是这个方法是一直受到社区的议论的:因为正是这个方法的存在使得 ViewController 的耦合特性上了一个档次。在某个 ViewController 中这个方法的存在时,就意味着我们需要确保当前的 ViewController 必须处于一个导航栈的上下文中,这是完全和上下文耦合的一种方式 (虽然我们也可以很蛋疼地用判断 navController 是不是 nil 来绕开,但是毕竟真的很丑,不是么)。

我们现在有了新的展示 viewController 的方法,-showViewController:sender: 以及 -showDetailViewController:sender:。调用这两个方法时,将顺着包括调用 vc 自身的响应链而上,寻找最近的实现了这个方法的 ViewController 来执行相应代码。在 iOS SDK 的默认实现中,在UISplitViewController 这样的容器类中,已经有这两个方法的实现方式,而UINavigationController 也实现了 -showViewController:sender: 的版本。对于在 navController 栈中的 vc,会调用 push 方式进行展示,而对 splitVC,showViewController:sender: 将在 MasterViewController 中进行 push。而 showDetailViewController:sender: 将根据水平方向的 Size 的情况进行选择:对于 Regular 的情况,将在 DetailViewController 中显示新的 vc,而对于 Compact 的情况,将由所在上下文情况发回给下级的 navController 或者是直接以 modal 的方式展现。关于这部分的具体内容,可以仔细看看这个示例项目和相关的文档 (beta版)。

这么设计的好处是显而易见的,首先是解除了原来的耦合,使得我们的 ViewController 可以不被局限于导航控制器上下文中;另外,这几个方法都是公开的,也就是说我们的 ViewController 可以实现这两个方法,截断响应链的响应,并实现我们自己的呈现方式。这在自定义 Container Controller 的时候会非常有用。

0 0