检测 UISplitViewController 何时更改显示模式

Detect when UISplitViewController changes display mode

我正在尝试使用 UISplitViewController,其中辅助控制器应该在 UISplitViewController 处于并排模式时公开 "close" 函数(通过按钮或按钮栏项),但应该隐藏其他时间的功能。我试着把它放在辅助视图控制器中:

override func viewWillAppear(_ animated: Bool) {
    if splitViewController!.primaryHidden {
        // hide the "close" UI artifact
    } else {
        // show the "close" UI artifact
    }
}

这会在首次显示辅助视图时正确设置 "close" 函数的可见性,但如果 UISplitViewController 在展开和折叠之间切换(例如,通过旋转 iPhone 6s Plus),那么这个函数就不会被再次调用(这是有道理的,因为辅助控制器仍然可见)。因此,"close" 函数保持其初始状态——隐藏或显示——即使 UISplitViewController 更改模式。

如何让 "close" 函数隐藏或显示以响应 UISplitViewController 模式的变化?

好的,我找到了一个简单的解决方案。我犯了一个新手错误。诀窍是覆盖 viewWillLayoutSubviews() 而不是 viewWillAppear(animated:)。然后一切如我所愿。似乎 viewWillLayoutSubviews() 每次包含 UISplitViewController 更改其显示模式时都会被调用(有时不止一次),而这正是我需要响应的。唯一的问题是 splitViewController 在其中一些调用中可能是 nil,因此需要像这样实现:

override func viewWillAppear(_ animated: Bool) {
    if let svc = splitViewController {
        if svc.primaryHidden {
            // hide the "close" UI artifact
        } else {
            // show the "close" UI artifact
        }
    }
}

作为我寻找解决方案的绊脚石的一部分,我尝试覆盖 traitCollectionDidChange(previousTraitCollection:)。 (我尝试这个是因为我想对设备旋转做出反应。)起初我以为我在做某事,因为每当设备旋转时也会调用此函数。有趣的是(并且,令人沮丧的是)我发现调用此函数时我的视图 splitViewController 属性 是 nil。这似乎很奇怪,因为当 UISplitViewController 重新配置自身时,viewDidDisappear(animated:)viewWillAppear(animated:) 都没有被调用。但我想为什么它应该是 nil 是另一天的问题。

UIViewControllerShowDetailTargetDidChangeNotification 通知:

// Sometimes view controllers that are using showViewController:sender and
// showDetailViewController:sender: will need to know when the split view
// controller environment above it has changed. This notification will be 
// posted when that happens (for example, when a split view controller is
// collapsing or expanding). The NSNotification's object will be the view
// controller that caused the change.
UIKIT_EXTERN NSNotificationName const UIViewControllerShowDetailTargetDidChangeNotification NS_AVAILABLE_IOS(8_0);

使用如下

- (void)viewDidLoad{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showDetailTargetDidChange:) name:UIViewControllerShowDetailTargetDidChangeNotification object:self.splitViewController];
}

- (void)showDetailTargetDidChange:(NSNotification *)notification{
    // changed from collapsed to expanded or vice versa
}

此 Apple 示例演示了 table 单元配件如何从纵向的披露指示器(表示将发生推送)更改为在更改为横向拆分视图时被删除: https://developer.apple.com/library/archive/samplecode/AdaptivePhotos/Introduction/Intro.html

关于 iOS 13 beta 的注意事项,将 addObserver 与对象 nil 一起使用,因为当前存在一个错误,他们使用错误的对象发送通知。他们使用来自内部 class 集群的新 UISplitViewControllerPanelImpl 而不是 UISplitViewController 对象。 http://www.openradar.appspot.com/radar?id=4956722791710720

供日后参考:

使用 UISplitViewControllerDelegate 怎么样?

它有一个名为

的方法
splitViewController:willChangeToDisplayMode:

这应该完全符合您的要求。

Documentation here