拆分视图控制器显示模式更改后更新应用程序UI?

时间:2014-10-02 19:30:24

标签: ios objective-c rotation ios8 uisplitviewcontroller

当拆分视图控制器的显示模式发生变化时,我需要能够更新我的应用程序的UI。具体来说,如果它从扩展界面变为折叠界面,我需要做一些事情,如果它从折叠变为扩展。

我目前通过traitCollectionDidChange处理此问题,虽然这对我的两个分割视图控制器似乎有效,但第三个不能正常工作。看起来这个方法过早被调用,所以当我检查displayMode以查看它是否UISplitViewcontrollerDisplayModeAllVisible时,拆分视图还没有更新到新的显示模式。因此它最终会删除我想要添加的按钮,或者在我想删除它们时添加它们。如果我在0.1秒之后延迟检查显示模式,displayMode值将正确表示旋转完成时的状态以及采取的相应操作。

我的问题是,有没有更好的方法来更新我的应用的用户界面,也许有办法知道displayMode何时发生变化?我不想冒太大的风险,但我也不想等到轮换完成以更新用户界面。延迟检查是一个非常脆弱的解决方案,可能很容易导致意外行为,有时它可能无法正常工作。

4 个答案:

答案 0 :(得分:2)

遇到类似问题,并在UISplitViewControllerDelegate

上发现了此委托方法
func targetDisplayModeForActionInSplitViewController(svc: UISplitViewController) -> UISplitViewControllerDisplayMode

唯一的问题是,当你问svc.displayMode时,它会告诉你它来自哪个模式而不是它的去向。但是,它足以阻止UISplitViewController进入特定状态。

    func targetDisplayModeForActionInSplitViewController(svc: UISplitViewController) -> UISplitViewControllerDisplayMode {
    switch svc.displayMode {
    case    .PrimaryOverlay :
        return .AllVisible
    case .AllVisible :
        return .PrimaryHidden
    case .PrimaryHidden :
        return .AllVisible
    case .Automatic :
        return .AllVisible
    default:
        return .AllVisible
    }
}

我能够用来知道我的UISplitViewController显示模式何时改变的另一个委托方法是

func splitViewController(svc: UISplitViewController, willChangeToDisplayMode displayMode: UISplitViewControllerDisplayMode)

然后,如果您处理对您来说重要的状态,则可以相应地更改视图

 func splitViewController(svc: UISplitViewController, willChangeToDisplayMode displayMode: UISplitViewControllerDisplayMode) {
    println("will change to display mode \(displayMode.rawValue)")


    if (displayMode == UISplitViewControllerDisplayMode.AllVisible) {
           //do something because EVERYTHING is visible      
    } else if (displayMode == UISplitViewControllerDisplayMode.PrimaryHidden) {
       //something else because the primary is GONE
    } else if (self.splitViewController?.displayMode == UISplitViewControllerDisplayMode.PrimaryOverlay){
       //handle primary overlay change
    }
}

答案 1 :(得分:1)

更强大的解决方案是在primaryViewControllerForCollapsingSplitViewController:中使用primaryViewControllerForExpandingSplitViewController:UISplitViewControllerDelegate

从文档中说出

  

如果您没有实现此方法,或者您的实现   返回nil,拆分视图控制器选择其主视图   控制器作为显示器。

因此,请实施这些方法来跟踪折叠和展开,然后返回nil,您仍然会获得默认行为。

答案 2 :(得分:0)

如果UISplitViewController:preferredDisplayModeUISplitViewControllerDisplayModeAutomatic,则其代表的targetDisplayModeForActionInSplitViewController:方法可让您从displayMode 后检索UISplitViewController 改变它的动作 - 例如displayModeButtonItem,滑动手势,旋转等。检索到的displayMode将不是UISplitViewControllerDisplayModeAutomatic - 它将反映实际的主要/次要显示状态

根据bolnad推断,targetDisplayModeForActionInSplitViewController:委托方法是为了指定displayMode在NEXT操作中使用的UISplitViewController(“它在哪里”) ,不需要很快。

在我的使用中,由于我的UISplitViewController.preferredDisplayMode始终为UISplitViewControllerDisplayModeAutomatic,因此我会在displayMode更改后触发我需要的任何活动,然后返回UISplitViewControllerDisplayModeAutomatic以供将来使用。

答案 3 :(得分:0)

  

如果我在0.1秒之后延迟检查该显示模式,则displayMode值正确表示旋转完成时将采取的措施,并采取适当的措施。

您要做的只是在显示模式更改后更新UI。当您设置0.1秒延迟时,它可以正常工作。

因此,解决方案非常简单,您只需将代码放在main thread runloop的末尾,使用GCD

// Swift3.0
DispatchQueue.main.async {
    // your code here
}

这意味着您的代码将在UI/Main Thread完成之前的工作(例如layoutSubviews,旋转或更改displayMode)后执行。如果Main/UI ThreadRunLoop,则设置0.1秒延迟的方法可能无法正常工作太忙了,不能在0.1秒内处理以前的工作

如果您不清楚,请参阅有关value here

的文件