浅析Split View Controller的collapse特性

Xcode自带的Master-Detail模板应用,在iPad和iPhone上有着不同的展示方式。今天来浅要介绍下如何在横屏时,使得SplitView在iPhone中的表现与在iPad中的保持一致。


iPad和iPhone中的不同

准备工作

打开Xcode,使用iOS->Application->Master-Detail Application模板创建一个App,取名随意。

运行后界面比较

以下分别是初始化的App在iPad、iPhone 6 Plus、iPhone 6中的横屏截图。

浅析Split View Controller的collapse特性_第1张图片
iPad横屏截图
浅析Split View Controller的collapse特性_第2张图片
iPhone 6 Plus横屏截图
浅析Split View Controller的collapse特性_第3张图片
iPhone 6 横屏截图

可以看到,App在iPad和Plus中的横屏表现几乎一致,除了Plus中没有显示最上面的状态栏和新增了Detail View左上角的按钮。但在其它iPhone中时,都只显示Master View,不同时显示Master和Detail View。这是由于什么原理造成的呢?


原理探究

Size Classes

想到iPhone 6 Plus、iPhone 6的屏幕尺寸不同,对应的Size Class也不尽相同,故找来各个iOS设备的Size Class做对比,如下表所示:

设备与方向
Compact Compact 除了Plus以外的所有横屏iPhone
Compact Regular 所有的竖屏iPhone
Regular Compact 横屏的Plus
Regular Regular iPad,不管横竖屏

可以看到,在横屏状态,iPad的宽和高都是Regular,Plus的宽是Regular,高是Compact,其余iPhone的宽和高都是Compact。故有可能只有在设备宽是Regular时,SplitView才会默认同时显示Master和Detail View。因此只要在iOS设备的interface environment发生改变时,检测设备的长和宽,若都为Compact,则将宽设为Regular,即可改变SplitView的默认collapse做法。

traitCollectionDidChange

当interface environment发生改变时,traitCollectionDidChange方法会被调用,可以在这里进行相关设置。

首先在Storyboard中拖入一个Navigation Controller,将其设为Initial View Controller,并将原先为Initial View Controller的Split View Controller设为它的root view controller。这样做是为了用新加的Navigation Controller来控制Split View Controller的traitCollection change行为。同时将Navigation Controller的Shows Navigation Bar选项取消勾选,使其不影响原有视图表现形式。

浅析Split View Controller的collapse特性_第4张图片
取消勾选Shows Navigation Bar

创建基于UINavigationController的RootViewController类,将其与新添加的Navigation Controller相对应。在该类中实现traitCollectionDidChange方法:

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    let splitViewController = self.viewControllers[0]
    
    if self.traitCollection.verticalSizeClass == .Compact && self.traitCollection.horizontalSizeClass == .Compact {
        let trait = UITraitCollection(horizontalSizeClass: .Regular)
        self.setOverrideTraitCollection(trait, forChildViewController: splitViewController)
    } else {
        self.setOverrideTraitCollection(nil, forChildViewController: splitViewController)
    }
}

以上代码的作用是,当检测到设备的长和宽都为Compact时,则这时候是在除了Plus以外的横屏iPhone中运行App,将其宽设为Regular,SplitView能够同时显示Master和Detail View;否则,不做任何重载。

AppDelegate微调

同时需要在AppDelegate.swift的didFinishLaunchingWithOptions函数进行微调,如下所示:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    let rootViewController = self.window!.rootViewController as! RootViewController
    let splitViewController = rootViewController.viewControllers[0] as! UISplitViewController
    
//        let splitViewController = self.window!.rootViewController as! UISplitViewController

    let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
    navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
    splitViewController.delegate = self
    return true
}

运行结果

在iPhone 6下重新运行App,横屏时的截图如下所示,说明修改成功。

浅析Split View Controller的collapse特性_第5张图片
iPhone6横屏截图

结语

以上是我的一些经验与心得,若有不足之处,请予指正。希望这篇文章对你有所帮助_

你可能感兴趣的:(浅析Split View Controller的collapse特性)