如何覆盖初始UIViewController的特征集合?(与故事板)

Ily*_*kin 11 uisplitviewcontroller xcode-storyboard swift ios8

我有一个针对iOS8的应用程序,初始视图控制器是UISplitViewController.我使用故事板,以便它为我实例化一切.

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

我发现我可以使用

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator!) { ... }
Run Code Online (Sandbox Code Playgroud)

但是,遗憾的是,只有方法可以覆盖子控制器特征集合:

setOverrideTraitCollection(collection: UITraitCollection!, forChildViewController childViewController: UIViewController!)
Run Code Online (Sandbox Code Playgroud)

我不能在我的UISplitViewController子类中为self做到这一点.

我查看了Apple 的示例应用程序Adaptive Photos.在这个应用程序作者中,作为root使用特殊的TraitOverrideViewController,并在他的viewController setter中使用一些魔法来使它全部工作.

这对我来说太可怕了.是否有任何方法可以覆盖特征?或者如果没有,我怎么能设法使用与故事板相同的黑客?换句话说,如何以root用户身份注入一些viewController只是为了处理带故事板的UISplitViewController的特征?

Ily*_*kin 7

好的,我希望还有另一种解决方法,但是现在我只是将Apple示例中的代码转换为Swift并将其调整为与Storyboard一起使用.

它有效,但我仍然相信这是一个很好的方式来存档这个目标.

我的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
    }
}
Run Code Online (Sandbox Code Playgroud)

要使其工作,您需要在故事板上添加一个新的UIViewController并使其成为初始值.将show segue从它添加到您的真实控制器,如下所示: 故事板

您需要将segue命名为"toSplitVC": segue名字

并将初始控制器设置为TraitOverride: 分配控制器

现在它也适合你.如果您发现更好的方法或任何缺陷,请告诉我.


Dav*_*son 5

我知道你在这里想要一个SWIFT翻译......你可能已经解决了这个问题.

下面是我花了相当长的时间试图解决 - 让我的SplitView在iPhone 6+上工作 - 这是一个Cocoa解决方案.

我的应用程序基于TabBar,SplitView具有导航控制器.最后,我的问题是setOverrideTraitCollection没有被发送到正确的目标.

@interface myUITabBarController ()

@property (nonatomic, retain) UITraitCollection *overrideTraitCollection;

@end

@implementation myUITabBarController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self performTraitCollectionOverrideForSize:self.view.bounds.size];
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    NSLog(@"myUITabBarController %@", NSStringFromSelector(_cmd));
    [self performTraitCollectionOverrideForSize:size];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}

- (void)performTraitCollectionOverrideForSize:(CGSize)size
{
    NSLog(@"myUITabBarController %@", NSStringFromSelector(_cmd));

    _overrideTraitCollection = nil;

    if (size.width > 320.0)
    {
        _overrideTraitCollection = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
    }

    [self setOverrideTraitCollection:_overrideTraitCollection forChildViewController:self];

    for (UIViewController * view in self.childViewControllers)
    {
        [self setOverrideTraitCollection:_overrideTraitCollection forChildViewController:view];
        NSLog(@"myUITabBarController %@ AFTER  viewTrait=%@", NSStringFromSelector(_cmd), [view traitCollection]);
    }
}

@end
Run Code Online (Sandbox Code Playgroud)


Ole*_*kiy 5

更新:

Apple 不建议这样做:

直接使用 traitCollection 属性。不要覆盖它。不提供自定义实现。

我不再覆盖这个属性了!现在我正在调用 overrideTraitCollectionForChildViewController:父 viewControler 类。

旧答案:

我知道自提出问题以来已经一年多了,但我认为我的回答将帮助像我这样没有通过接受的答案取得成功的人。

解决方案非常简单,您只需覆盖traitCollection:方法即可。这是我的应用程序中的一个示例:

- (UITraitCollection *)traitCollection {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        return super.traitCollection;
    } else {
        switch (self.modalPresentationStyle) {
            case UIModalPresentationFormSheet:
            case UIModalPresentationPopover:
                return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];

            default:
                return super.traitCollection;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果控制器显示为弹出框或表单,则该想法是在 iPad 上强制使用 Compact size 类。

希望能帮助到你。