Unwind segue 在非模态时不会关闭自适应弹出窗口呈现
Unwind segue doesn't dismiss adaptive popover presentation when not modal
iOS 9 beta 的更新:Apple 可能已经为 iOS 9 修复了此问题。如果您为 iOS 8 解决了这个问题,确保它在 iOS 9.
上也能正常工作
在情节提要中,我创建了一个弹出式展示转场以通过按钮展示导航和视图控制器,并创建了一个展开转场。
在纵向模式下,模态(全屏)显示如预期的那样 unwound/dismissed。
在横向模式下,也会调用展开转场,但是弹出窗口显示不会自动关闭。
我是不是错过了什么连接?我必须自己关闭弹出窗口显示吗?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
if ([[segue identifier] isEqualToString:@"showSelectBookChapter"])
{
UINavigationController *navigationController = segue.destinationViewController;
if ([navigationController.topViewController isKindOfClass:[BIBLESelectViewController class]])
{
BIBLESelectViewController *selectViewController = (BIBLESelectViewController *)navigationController.topViewController;
selectViewController.initialBookChapterVerse = self.bookChapterVerse;
}
}
}
- (IBAction)unwindToBIBLEChapterViewController:(UIStoryboardSegue *)segue
{
if ([segue.identifier isEqualToString:@"unwindToBIBLEChapterViewController"]) {
if ([segue.sourceViewController isKindOfClass:[BIBLESelectViewController class]])
{
BIBLESelectViewController *sourceViewController = (BIBLESelectViewController *)segue.sourceViewController;
self.bookChapterVerse = sourceViewController.selectedBookChapterVerse;
[self.tableView reloadData];
}
}
}
更新:
在查看了 gabbler 的示例代码之后,我将问题缩小为在单视图应用程序中弹出窗口关闭正常,但在主从应用程序中没有。
更新二:
这是层次结构的样子(为了简单起见省略了导航控制器),以回答 Luis 提出的问题:
- 拆分视图控制器
- 主视图控制器
- 详细视图控制器
- 章节视图控制器(模态页面sheet)
- Select 视图控制器(有问题的弹出窗口展开到章节视图控制器,但不会关闭)
正如我在之前的更新中提到的,我创建了一个新的 master/detail 模板,并直接从详细视图(中的一个按钮)简单地呈现了一个弹出框。它不会解雇。
它 is/must 是 popOver segue 的一种行为,在正常情况下或经常我们需要 popOver 保持在视图中,如果 segue 显示一些重要的东西很烦人,我们只是因为旋转而丢失了该信息设备,我想这就是本机行为的原因。因此,如果我们想让它自动关闭,我们必须自己做出这种行为,这是可行的:
在方法 - (void)viewDidLoad
中 detailViewController.m 添加:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
然后创建这个方法:
- (void) orientationChanged:(NSNotification *)note{
UIDevice * device = note.object;
//CGRect rect = [[self view] frame];
switch(device.orientation)
{
default:
[self dismissViewControllerAnimated:YES completion:nil];
break; }}
你说过在单一视图中会发生你想要的事情,但我在使用 popOvers 时从未见过这种行为。
我运行也遇到过这个问题。我从主视图控制器 (UISplitViewController) 模态地(作为一种形式 sheet)呈现一个视图控制器。问题只出现在 iPad 上(可能也是横向模式下的 iPhone 6+,但我没有检查)。我最终在我的展开操作方法中执行了以下操作(使用 Swift),并且效果很好。
if !segue.sourceViewController.isBeingDismissed() {
segue.sourceViewController.dismissViewControllerAnimated(true, completion: nil)
}
如果您从 嵌入导航控制器中的视图控制器 作为弹出窗口进行搜索,相应的展开将无法关闭弹出窗口。
这是 -[UINavigationController segueForUnwindingToViewController:fromViewController:identifier]
中的错误。嵌入的导航控制器应该提供一个 segue 来关闭弹出窗口,但它没有。然后解决方法是覆盖它并提供一个工作 segue,我们可以从嵌入式视图控制器获得它。
这是一个只处理展开到导航堆栈的顶视图控制器的部分解决方案:
@implementation MyNavigationController
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
fromViewController:(UIViewController *)fromViewController
identifier:(NSString *)identifier
{
if (toViewController == self.topViewController && fromViewController.presentingViewController == self)
return [toViewController segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
else
return [super segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
}
@end
它适用于 iOS 8 landscape/portrait iPad 和 landscape/portrait iPhone。逻辑应该足够健壮以在 iOS 9.
上生存
mbeaty 的修复很好,但正如其他人指出的那样,这个错误似乎知道在 iOS 9 中修复,并且它也不适用于通用设备设计。我已经调整了他的回答来处理这两种情况。这是代码:
@IBAction func yourUnwindSegue(segue: UIStoryboardSegue) {
if #available(iOS 9, *) {
return // bug fixed in iOS 9, just return and let it work correctly
}
// do the fix for iOS 8 bug
// access your SplitViewController somehow, this is one example
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let splitVC = appDelegate.window!.rootViewController as! YourSplitViewController
// if the source isn't being dismissed and the splitView isn't
// collapsed (ie both windows are showing), do the hack to
// force it to dismiss
if !segue.sourceViewController.isBeingDismissed() && splitVC.collapsed == false {
segue.sourceViewController.dismissViewControllerAnimated(true, completion: nil)
}
}
这首先检查 iOS 9 是否为 运行,然后退出,因为错误似乎已修复。这将防止多个视图被忽略的问题。还要确保仅在 splitView 显示两个 windows 时才进行此修复(以使其仅在 iPad 和 iPhone 6 Plus 横向以及未来的设备上发生)我添加了检查以进行确保它没有折叠。
我没有详尽地检查过这个,但它似乎有效。也不是说我的应用程序设置为 iOS 7 分钟,我不知道这个错误是否存在,所以如果你支持 iOS 8.[=11 以下,你可能需要调查一下=]
iOS 9 beta 的更新:Apple 可能已经为 iOS 9 修复了此问题。如果您为 iOS 8 解决了这个问题,确保它在 iOS 9.
上也能正常工作在情节提要中,我创建了一个弹出式展示转场以通过按钮展示导航和视图控制器,并创建了一个展开转场。
在纵向模式下,模态(全屏)显示如预期的那样 unwound/dismissed。
在横向模式下,也会调用展开转场,但是弹出窗口显示不会自动关闭。
我是不是错过了什么连接?我必须自己关闭弹出窗口显示吗?
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
if ([[segue identifier] isEqualToString:@"showSelectBookChapter"])
{
UINavigationController *navigationController = segue.destinationViewController;
if ([navigationController.topViewController isKindOfClass:[BIBLESelectViewController class]])
{
BIBLESelectViewController *selectViewController = (BIBLESelectViewController *)navigationController.topViewController;
selectViewController.initialBookChapterVerse = self.bookChapterVerse;
}
}
}
- (IBAction)unwindToBIBLEChapterViewController:(UIStoryboardSegue *)segue
{
if ([segue.identifier isEqualToString:@"unwindToBIBLEChapterViewController"]) {
if ([segue.sourceViewController isKindOfClass:[BIBLESelectViewController class]])
{
BIBLESelectViewController *sourceViewController = (BIBLESelectViewController *)segue.sourceViewController;
self.bookChapterVerse = sourceViewController.selectedBookChapterVerse;
[self.tableView reloadData];
}
}
}
更新二: 这是层次结构的样子(为了简单起见省略了导航控制器),以回答 Luis 提出的问题:
- 拆分视图控制器
- 主视图控制器
- 详细视图控制器
- 章节视图控制器(模态页面sheet)
- Select 视图控制器(有问题的弹出窗口展开到章节视图控制器,但不会关闭)
- 章节视图控制器(模态页面sheet)
正如我在之前的更新中提到的,我创建了一个新的 master/detail 模板,并直接从详细视图(中的一个按钮)简单地呈现了一个弹出框。它不会解雇。
它 is/must 是 popOver segue 的一种行为,在正常情况下或经常我们需要 popOver 保持在视图中,如果 segue 显示一些重要的东西很烦人,我们只是因为旋转而丢失了该信息设备,我想这就是本机行为的原因。因此,如果我们想让它自动关闭,我们必须自己做出这种行为,这是可行的:
在方法 - (void)viewDidLoad
中 detailViewController.m 添加:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:[UIDevice currentDevice]];
然后创建这个方法:
- (void) orientationChanged:(NSNotification *)note{
UIDevice * device = note.object;
//CGRect rect = [[self view] frame];
switch(device.orientation)
{
default:
[self dismissViewControllerAnimated:YES completion:nil];
break; }}
你说过在单一视图中会发生你想要的事情,但我在使用 popOvers 时从未见过这种行为。
我运行也遇到过这个问题。我从主视图控制器 (UISplitViewController) 模态地(作为一种形式 sheet)呈现一个视图控制器。问题只出现在 iPad 上(可能也是横向模式下的 iPhone 6+,但我没有检查)。我最终在我的展开操作方法中执行了以下操作(使用 Swift),并且效果很好。
if !segue.sourceViewController.isBeingDismissed() {
segue.sourceViewController.dismissViewControllerAnimated(true, completion: nil)
}
如果您从 嵌入导航控制器中的视图控制器 作为弹出窗口进行搜索,相应的展开将无法关闭弹出窗口。
这是 -[UINavigationController segueForUnwindingToViewController:fromViewController:identifier]
中的错误。嵌入的导航控制器应该提供一个 segue 来关闭弹出窗口,但它没有。然后解决方法是覆盖它并提供一个工作 segue,我们可以从嵌入式视图控制器获得它。
这是一个只处理展开到导航堆栈的顶视图控制器的部分解决方案:
@implementation MyNavigationController
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
fromViewController:(UIViewController *)fromViewController
identifier:(NSString *)identifier
{
if (toViewController == self.topViewController && fromViewController.presentingViewController == self)
return [toViewController segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
else
return [super segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
}
@end
它适用于 iOS 8 landscape/portrait iPad 和 landscape/portrait iPhone。逻辑应该足够健壮以在 iOS 9.
上生存mbeaty 的修复很好,但正如其他人指出的那样,这个错误似乎知道在 iOS 9 中修复,并且它也不适用于通用设备设计。我已经调整了他的回答来处理这两种情况。这是代码:
@IBAction func yourUnwindSegue(segue: UIStoryboardSegue) {
if #available(iOS 9, *) {
return // bug fixed in iOS 9, just return and let it work correctly
}
// do the fix for iOS 8 bug
// access your SplitViewController somehow, this is one example
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let splitVC = appDelegate.window!.rootViewController as! YourSplitViewController
// if the source isn't being dismissed and the splitView isn't
// collapsed (ie both windows are showing), do the hack to
// force it to dismiss
if !segue.sourceViewController.isBeingDismissed() && splitVC.collapsed == false {
segue.sourceViewController.dismissViewControllerAnimated(true, completion: nil)
}
}
这首先检查 iOS 9 是否为 运行,然后退出,因为错误似乎已修复。这将防止多个视图被忽略的问题。还要确保仅在 splitView 显示两个 windows 时才进行此修复(以使其仅在 iPad 和 iPhone 6 Plus 横向以及未来的设备上发生)我添加了检查以进行确保它没有折叠。
我没有详尽地检查过这个,但它似乎有效。也不是说我的应用程序设置为 iOS 7 分钟,我不知道这个错误是否存在,所以如果你支持 iOS 8.[=11 以下,你可能需要调查一下=]