iPad模态控制器在旋转后被解除。

6
我正在使用一个故事板segue作为“表单表格”来呈现一个模态视图。问题是,当我显示这个视图后旋转iPad,视图会从视图中移除/关闭。
我不知道为什么,似乎只在从纵向开始旋转到横向时才会发生。
如果我从横向开始显示视图然后旋转它,则可以正常地保留在屏幕上。
有什么想法吗?
编辑——
全屏模态视图在旋转后也被关闭!
在演示代码中没有任何特殊的情况,这是一个全屏模态:
EditViewController *editView = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"editViewController"];
editView.delegate = self;
editView.image = image;
editView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;

[self presentViewController:editView animated:YES completion:nil];

这在iOS 6和iOS 7上都会发生。
编辑2 ---- 忘了提一下,我是从一个UISplitViewController的左侧/主视图控制器中呈现模态视图。

1
你能展示呈现模型的代码吗?这是哪个iOS版本? - Toseef Khilji
1
嘿,你看过这篇帖子吗?这个人有类似的问题。http://stackoverflow.com/a/13126655/437146 - NightFury
你能在主视图控制器的layoutSubviews中检查吗?这将在旋转时被调用,可能有代码可以解除这些。发布更多的代码会有所帮助。 - Jesse
在旋转后,viewDidLayoutSubviews 函数被调用一次,但是当模态窗口显示时,它会在旋转后被调用两次,然后模态窗口消失。 - Darren
擦掉它,每次显示主程序时都会调用两次。 - Darren
显示剩余6条评论
7个回答

3

虽然有点晚,但是对我行之有效的方法是在这之前

[self presentViewController:aController animated:YES completion:nil];

解散主控制器,添加以下代码行。
[self.splitViewController setPreferredDisplayMode:UISplitViewControllerDisplayModePrimaryHidden];
[self.splitViewController setPreferredDisplayMode:UISplitViewControllerDisplayModeAutomatic];

然后呈现您的控制器


太好了!我卡在这里有一段时间了,谢谢你。 - Romain
我遇到的难题得到了简单的解决方案。谢谢! - Justin Domnitz

1
这不是一个错误,而是关于UISplitViewController的限制。当masterViewController(一个UIPopoverController)可以被解除时,问题就存在了。以下是它的工作原理,假设您的应用程序允许在纵向模式下解除masterViewController,但在横向模式下不允许。
在纵向模式下,当masterViewController可见时,如果您从masterViewController中的viewController呈现一个模态视图,然后旋转到横向模式,该模态视图将在iOS7中消失,并且应用程序在iOS8中不会旋转。iOS8引入了一种条件来防止iOS7的不良体验。在将masterViewController从popoverController移动到splitViewController中包含的viewController的过程中,iOS7会丢失模态视图。
模态视图需要从splitViewController而不是从masterViewController中呈现。唯一的问题是,在纵向模式下,模态视图会被呈现在masterViewController下方。我的解决方案是解除masterViewController,然后呈现模态视图。
有几种方法可以实现此结果,具体取决于代码的复杂程度。以下是我在我的应用程序中如何实现此操作的方式。
首先,我子类化了UISplitViewController,以便引用popoverController。我使用委托转发来在内部和外部访问委托方法。以下是.h文件。
// MainSplitViewController.h

#import <UIKit/UIKit.h>

@interface MainSplitViewController : UISplitViewController
@property (nonatomic, weak, readonly) UIPopoverController* primaryColumnController;
@end

而且 .m

// MainSplitViewController.m

#import "MainSplitViewController.h"

@interface MainSplitViewController () <UISplitViewControllerDelegate>
@property (nonatomic, weak) id<UISplitViewControllerDelegate> externalDelegate;
@property (nonatomic, weak) UIPopoverController* primaryColumnController;
@end

@implementation MainSplitViewController

- (instancetype)init {
    self = [super init];
    if (self) {
        self.delegate = self;
    }
    return self;
}


#pragma mark - Split View Controller Delegate

- (void)splitViewController:(UISplitViewController *)svc popoverController:(UIPopoverController *)pc willPresentViewController:(UIViewController *)aViewController {
    self.primaryColumnController = pc;

    if ([(id)self.externalDelegate respondsToSelector:_cmd]) {
        [self.externalDelegate splitViewController:svc popoverController:pc willPresentViewController:aViewController];
    }
}


#pragma mark - Delegate Forwarder

- (void)setDelegate:(id<UISplitViewControllerDelegate>)delegate {
    [super setDelegate:nil];
    self.externalDelegate = (delegate != self) ? delegate : nil;
    [super setDelegate:delegate ? self : nil];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    id delegate = self.externalDelegate;
    return [super respondsToSelector:aSelector] || [delegate respondsToSelector:aSelector];
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    id delegate = self.externalDelegate;
    return [delegate respondsToSelector:aSelector] ? delegate : [super forwardingTargetForSelector:aSelector];
}

@end

下一步,我在UIViewController上创建了一个类扩展。
// UIViewController+Popover.h

#import <UIKit/UIKit.h>

@interface UIViewController (Popover)
- (UIViewController *)popoverPresentingViewController;
@end

而且 .m

// UIViewController+Popover.m

#import "UIViewController+Popover.h"
#import "MainSplitViewController.h"

@implementation UIViewController (Popover)

- (UIViewController *)popoverPresentingViewController {
    UIViewController* viewController = self;

    if ([self.splitViewController isKindOfClass:[MainSplitViewController class]]) {
        viewController = self.splitViewController;

        MainSplitViewController* mainSplitViewController = (MainSplitViewController *)self.splitViewController;

        if (mainSplitViewController.primaryColumnController.popoverVisible) {
            [mainSplitViewController.primaryColumnController dismissPopoverAnimated:YES];
        }
    }

    return viewController;
}

@end

现在,无论您在哪里呈现模态视图,都不要调用[self presentViewController: ...,而是调用[self.popoverPresentingViewController presentViewController: ...]。请记得导入UIViewController+Popover.h。

1
摆脱它:editView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; 这将解决您所遇到的问题。以表单表格形式呈现在iPad上的模态视图控制器不会使用该转换样式正确旋转。

很抱歉,那并不起作用。问题仍然存在。而且使用“in”这一行,我确实看到了一个水平翻转的过渡效果。 - Darren
抱歉,我应该提到,上面粘贴的代码是用于全屏模态而不是表单表格模态。问题发生在两者上。 - Darren
1
抱歉回答不正确。几年前是这样的,但我刚刚重新验证了一下,现在已经不是这样了。使用当前的iOS,如果从主视图控制器呈现,无论使用哪种转换样式,模态视图在从纵向到横向时都会被解除。看起来分割视图控制器可能在某个地方内部调用了dismissViewController。我认为我们应该提交错误报告。 - Norman G

1

很难确定出现这种情况的原因及其发生的方式和原因,我发现它也会在UIPopover中发生,当你旋转它时,UIPopover会隐藏,因为???

因此,如果您想保留您的视图,只需在旋转后再次调用您的控制器即可获得良好的用户体验。


我认为问题实际上出在主视图和模态的所有权上。因为主视图实际上是一个弹出窗口,在旋转时显示和移除。 - Darren
UISplitViewController已经像弹出视图一样了,如果你从竖屏旋转到横屏,它也会被取消。 - Retro

0

问题:

以模态方式呈现视图控制器时,旋转会导致其被解除。

方法:

  • 设置UISplitViewControllerDelegate
  • 使用UISplitViewControllerDelegate方法
  • 在实例变量中保存模态视图控制器的引用
  • 检查您的模态视图控制器的呈现视图控制器是否存在。
  • 如果存在,则无需进行任何操作,否则只需不带任何动画呈现即可。

UISplitViewControllerDelegate方法:

func primaryViewController(forCollapsing splitViewController: UISplitViewController) -> UIViewController? {

    if let someModalViewController = someModalViewController, 
        someModalViewController.presentingViewController == nil {

        let masterViewController = viewControllers.first

        masterViewController?.present(someModalViewController,
                                      animated: false) {

        }
    }

    return nil
}

func primaryViewController(forExpanding splitViewController: UISplitViewController) -> UIViewController? {

    if let someModalViewController = someModalViewController, 
        someModalViewController.presentingViewController == nil {

        let masterViewController = viewControllers.first

        masterViewController?.present(someModalViewController,
                                      animated: false) {

        }
    }

    return nil
}

注意:

  • UISplitViewControllerDelegate 有很多方法,一开始可能会让人望而生畏,但如果你花些时间进行实验,就能达到你想要的效果。
  • 它具有细粒度的访问权限。

0

你的问题最接近我的错误,从modalView返回时,parentView将切换到应用程序打开时的方向。
视觉上看,模态视图会旋转然后返回。

我通过完全删除模态视图并使用以下方法解决了它

[self.navigationController pushViewController: <the View(not modal now)>]

不要使用-

[self presentViewController:<Modal View>]

我认为这是因为导航控制器不拥有模态视图,因此在从模态视图返回时重新加载到不正确的方向。


0

我很晚了,但是试试这个。对我有效。

[self.splitViewController presentViewController:editView animated:YES completion:nil];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接