一尘不染

如何为初始UIViewController覆盖特征收集?(使用情节提要)

swift

我有一个针对iOS8的应用,初始视图控制器是UISplitViewController。我使用情节提要,以便
为我实例化所有内容。

由于我的设计,我需要SplitViewController在iPhone上以纵向模式显示主视图和详细视图。因此,我正在寻找一种方法来对此UISplitViewController 覆盖特征收集。

我发现我可以使用

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator!) { ... }

但是,不幸的是,只有一些方法可以覆盖子控制器特征集:

setOverrideTraitCollection(collection: UITraitCollection!, forChildViewController childViewController: UIViewController!)

and I can’t do so for self in my UISplitViewController subclass.
而且我不能在UISplitViewController子类中自行这样做。

我检查了 Apple 的示例应用“ Adaptive
Photos

。并且在此应用程序中,作者使用特殊的TraitOverrideViewController作为
root用户,并在其viewController setter中使用一些魔术来使其全部起作用。


阅读 236

收藏
2020-07-07

共1个答案

一尘不染

好的,我希望有另一种解决方法,但是现在我只是将代码从Apple示例转换为Swift,并对其进行了调整以与Storyboards一起使用。

它有效,但是我仍然认为这是实现此目标的糟糕方法。

我的TraitOverride.swift:

import UIKit

class TraitOverride: UIViewController {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    var forcedTraitCollection: UITraitCollection? {
        didSet {
            updateForcedTraitCollection()
        }
    }

    override func viewDidLoad() {
        setForcedTraitForSize(view.bounds.size)
    }

    var viewController: UIViewController? {
        willSet {
            if let previousVC = viewController {
                if newValue !== previousVC {
                    previousVC.willMoveToParentViewController(nil)
                    setOverrideTraitCollection(nil, forChildViewController: previousVC)
                    previousVC.view.removeFromSuperview()
                    previousVC.removeFromParentViewController()
                }
            }
        }

        didSet {
            if let vc = viewController {
                addChildViewController(vc)
                view.addSubview(vc.view)
                vc.didMoveToParentViewController(self)
                updateForcedTraitCollection()
            }
        }
    }

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator!) {
        setForcedTraitForSize(size)
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    }

    func setForcedTraitForSize (size: CGSize) {

        let device = traitCollection.userInterfaceIdiom
        var portrait: Bool {
            if device == .Phone {
                return size.width > 320
            } else {
                return size.width > 768
            }
        }

        switch (device, portrait) {
        case (.Phone, true):
            forcedTraitCollection = UITraitCollection(horizontalSizeClass: .Regular)
        case (.Pad, false):
            forcedTraitCollection = UITraitCollection(horizontalSizeClass: .Compact)
        default:
            forcedTraitCollection = nil
        }
    }

    func updateForcedTraitCollection() {
        if let vc = viewController {
            setOverrideTraitCollection(self.forcedTraitCollection, forChildViewController: vc)
        }
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        performSegueWithIdentifier("toSplitVC", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
        if segue.identifier == "toSplitVC" {
            let destinationVC = segue.destinationViewController as UIViewController
            viewController = destinationVC
        }
    }

    override func shouldAutomaticallyForwardAppearanceMethods() -> Bool {
        return true
    }

    override func shouldAutomaticallyForwardRotationMethods() -> Bool {
        return true
    }
}

要使其工作,您需要在情节提要板上添加新的UIViewController并将其设置为初始。将show segue从其中添加到您的真实控制器中

现在它也应该为您工作。如果您找到更好的方法或此方法有任何缺陷,请告诉我。

2020-07-07