简体   繁体   English

iOS 8中的UISplitViewController状态恢复

[英]UISplitViewController state restoration in iOS 8

On iOS 8, UISplitViewController appears to save and restore the state of its subviews, for example, whether the master view is hidden or not. 在iOS 8上,UISplitViewController似乎可以保存和恢复其子视图的状态,例如,是否隐藏主视图。

This is undesirable because my app should always show the master view in landscape and always hide it in portrait. 这是不可取的,因为我的应用程序应始终在横向显示主视图并始终以纵向隐藏它。 If the user closes the app in landscape (landscape state is saved) and reopens it in portrait (landscape state is restored), then the UISplitViewController shows the master view in the wrong configuration. 如果用户以横向关闭应用程序(保存横向状态)并以纵向重新打开(横向状态已恢复),则UISplitViewController将以错误的配置显示主视图。

I still need to supply a restoration identifier to the UISplitViewController so that is subview controllers have their own state saved and restored. 我仍然需要为UISplitViewController提供恢复标识符,以便子视图控制器保存和恢复自己的状态。 So how does one prevent UISplitViewController from restoring its own state, or override this behavior? 那么如何防止UISplitViewController恢复自己的状态,或者覆盖这种行为呢?

I solved this by subclassing UISplitViewController and overriding - (void)decodeRestorableStateWithCoder:(NSCoder *)coder to do nothing. 我通过继承UISplitViewController并重写- (void)decodeRestorableStateWithCoder:(NSCoder *)coder来解决这个问题。 This way the split view controller does not have an opportunity to restore its views, but its child view controllers still participate in state restoration. 这样,拆分视图控制器没有机会恢复其视图,但其子视图控制器仍然参与状态恢复。

The first thing needed when implementing UI State Restoration is changing from using didFinishLaunchingWithOptions to willFinishLaunchingWithOptions. 实现UI状态恢复时所需的第一件事就是从使用didFinishLaunchingWithOptions变为willFinishLaunchingWithOptions。 If you set the delegate now in the willFinish the collapse will be called as expected. 如果您现在在willFinish中设置委托,则将按预期调用折叠。 The issue was likely the delegate was set too late and it had already collapsed without your special handling. 问题很可能是代表设置得太晚了,如果没有你的特殊处理,它已经崩溃了。

Another issue is that the restoration paths to the controllers are different when in landscape and portrait so could be getting in a weird state. 另一个问题是,当在横向和纵向时,控制器的恢复路径是不同的,因此可能处于奇怪的状态。 Because of the change it can't automatically find the existing detail view controller and creates new instances and either both or one of them likely get thrown away by the split view delegate because of misconfiguration of the detail item. 由于更改,它无法自动查找现有详细信息视图控制器并创建新实例,并且由于详细信息项的配置错误,拆分视图委托可能会丢弃其中一个或其中一个实例。 In the State Restoration docs under "Recreate Your View Controllers" on step 3 it says it looks for an already created view controller with the same path which sadly fails when restoring after an orientation/trait change because the path is different. 在第3步“重新创建视图控制器”下的状态恢复文档中,它表示它会查找已创建的具有相同路径的视图控制器,这种路径在方向/特征更改后因路径不同而进行恢复时可悲地失败。 So it falls back to step 4 and creates a brand new empty misconfigured detail controller and is the reason you see the wrong configuration of controllers. 所以它回到第4步并创建一个全新的空配置错误的细节控制器,这就是你看到控制器配置错误的原因。

To understand the restoration identifier paths, implement application:viewControllerWithRestorationIdentifierPath:coder: in the app delegate and output the path components you'll see in portrait the last to be restored looks like: 要了解恢复标识符路径,请实现应用程序:viewControllerWithRestorationIdentifierPath:coder:在app委托中输出您将在纵向中看到的要恢复的最后一个路径组件,如下所示:

SplitViewController,
MasterNavigationController,
DetailNavigationController,
DetailViewController

...which corresponds the single hierarchy primary of the split view controller (note: DetailNavigationController is a hidden nested navigation controller in this configuration). ...对应于拆分视图控制器的单层次主要(注意:DetailNavigationController是此配置中隐藏的嵌套导航控制器)。

And in landscape the last two to be restored are: 在景观中,最后两个要恢复的是:

SplitViewController,
MasterNavigationController,
MasterViewController

and

SplitViewController,
DetailNavigationController,
DetailViewController

...which corresponds to the primary and secondary controller hierarchies of the split view. ...对应于拆分视图的主要和次要控制器层次结构。

So now knowing the restoration path to DetailViewController can be different, you can understand that if you try to automatically restore a portrait path while the storyboard has initlaised in landscape it won't find that detail view controller and resort to creating a new one. 因此,现在知道DetailViewController的恢复路径可能不同,您可以理解,如果您尝试在故事板在横向中初始化时自动恢复纵向路径,则无法找到该详细视图控制器并求助于创建新的控制器。 So I think the solution is to give it a helping hand to find it regardless of how the restoration path was saved: 因此,我认为无论恢复路径如何保存,解决方案都是帮助找到它:

- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder{
    if([identifierComponents.lastObject isEqualToString:@"DetailViewController"]){
        UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
            UINavigationController *secondaryNavigationController = splitViewController.viewControllers.lastObject;;
            DetailViewController *detail = (DetailViewController *)secondaryNavigationController.viewControllers.firstObject;
        return detail;
    }
    return nil;
}

Now the restoration will correctly use the existing detail controller which is configured correctly and it won't be thrown away by the split view delegate which was resulting in you being left with the master. 现在,恢复将正确使用正确配置的现有详细控制器,并且拆分视图委托不会抛弃它,导致您留下主控。

Another way this issue can manifest is seeing two detail controllers pushed onto the navigation stack after restoration, which is what happens if you force the split view delegate to not throw away the initial detail controller, and when the restoration creates another one you end up with two pushed on! 此问题可以表现的另一种方式是在恢复后看到两个细节控制器被推入导航堆栈,如果您强制拆分视图委托不丢弃初始细节控制器,并且当修复创建另一个时,您最终会发生这种情况两个推!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM