iPad/iOS7:在“页面”模态视图控制器中,从中呈现“全屏”视图控制器后,其表现异常

9
我的iPad应用程序使用“页面”展示风格打开模态视图控制器。正如您所知,“页面”展示风格不会覆盖呈现视图控制器的状态栏,以指示页面展示。

Initial view controller

Page modal view controller

从模态视图控制器中打开 UIImagePickerController 来拍照。 UIImagePickerController 采用“全屏”呈现样式。在关闭图像选择器后,呈现模态视图控制器会变高 20px 并覆盖初始视图控制器的状态栏。我试图用简单的 UINavigationController 替换 UIImagePickerController,但这也破坏了我的模态视图控制器。
以下是屏幕截图: Full screen view controller

Broken modal view controller

他们唯一恢复“页面”视图控制器大小的方法是在返回到“页面”视图控制器后更改viewController.view.superview.superview.superview.superview框架的高度。但这真的很奇怪。
还有其他方法可以修复在解除嵌套模态视图控制器后呈现“页面”模态视图控制器吗?
更新: 我使用了这样奇怪的代码来解决我的问题:
#define STATUS_BAR_HEIGHT 20
#define IPAD_PORTRAIT_HEIGHT 1004
#define IPAD_LANDSCAPE_HEIGHT 748
UIView *superview = nil;

// In case of this view controller included in navigationController we have to use superview of navigation's controller view
if (self.navigationController)
    superview = self.navigationController.view.superview;
else
    superview = self.view.superview;

CGRect r = superview.frame;

// Sometimes we have to fix height + origin, sometimes only height (becase view has bottom magnifying)
// In landscape orientation we have to fix 'width' instead of 'height', because that view controller always works in 'portrait' mode
if (self.interfaceOrientation == UIInterfaceOrientationPortrait && r.size.height > IPAD_PORTRAIT_HEIGHT) {
    r.origin.y = STATUS_BAR_HEIGHT;
    r.size.height = IPAD_PORTRAIT_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationMaskPortraitUpsideDown && r.size.height > IPAD_PORTRAIT_HEIGHT) {
    r.size.height = IPAD_PORTRAIT_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
    r.size.width = IPAD_LANDSCAPE_HEIGHT;
    r.origin.x = STATUS_BAR_HEIGHT;
}
else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
    r.size.width = IPAD_LANDSCAPE_HEIGHT;
}

superview.frame = r;

我不相信没有更优雅的解决方案。有什么想法可以改进吗?
更新2:我刚刚提交了一个错误报告。你可以在那里跟踪它: rdar://15949644 更新3:这是我的示例项目: link

这是一个已知的苹果漏洞。在iOS7.1中尚未修复。请确保打开漏洞报告。 - Léo Natan
@iDev,请检查第三个更新。 - Vitaly S.
1
这个问题很容易复现,你的解决方法很好。 - Léo Natan
@pssdbt,不,我是正确的。那个"superview"(父视图)总是以相同的方向工作,所以如果你的视图处于横向方向,那么"superview"无论如何都是纵向的,因此你需要改变它的宽度而不是高度。你可以下载示例项目并尝试使用它。 - Vitaly S.
@VitalyS。在我的应用程序中,模态框向左边缘偏移了20像素,而不是保持居中,就像听起来的那样。我进行了更改,现在不会再出现这种问题了。奇怪的问题。 - jeffff
显示剩余7条评论
5个回答

2

目前没有很好的解决方案,这是一个苹果的bug,直到修复为止,你需要绕过它。在iOS 7.1中仍未得到解决。我曾尝试解决此问题,但发现我也在实施相同的解决方案。它很丑,但可以解决问题。

关于这个设计,我的猜测是苹果忽视了这个问题是因为全屏显示视图控制器不是苹果惯常做法。当然这并不是一个借口,有时候没有其他选择,只能全屏显示(例如我们必须打开相机视图,这必须在全屏状态下打开)。也许你可以改变你的设计来适应苹果的bug。


实际上我遇到了这个问题,因为我必须呈现 UIImagePickerController,所以我没有其他选择。谢谢。 - Vitaly S.
我们认为这个问题的优先级较低,基本上会让苹果自己来解决它们的问题。 - Léo Natan

1
"确保呈现模态视图的ViewController位于NavigationController中,这种奇怪的情况应该就会停止了。" 我最初的答案是错误的。 更新: 这确实听起来像一个bug,尽管从用户体验的角度来看,你不应该真正遇到这个问题。在“页面”呈现样式中呈现一个视图控制器,然后以全屏模式再呈现另一个视图控制器似乎有些不妥。我认为这从一开始就是糟糕的设计,因此它不像你期望的那样运作可能是因为设置它的人没有预料到有人会这样使用它。
我会像我的初始答案所述那样,将您的模态呈现的视图控制器嵌入导航控制器中,并将UIImagPickerViewController推入其中,或者将其动画添加到您的视图中,就像另一个页面样式的模态视图一样呈现出来。如果这是你想要的效果。
这些都不是完美的解决方案,更完美的解决方案是考虑你的应用程序流程,重新评估事物的呈现方式。

即使使用NavigationController,问题仍然存在。 - Vitaly S.
这里有一个示例项目。你可以下载并尝试操作它。 - Vitaly S.

-1

UIImagePicker(或更广泛地说,UINavigationController)在应用程序中不遵守任何状态栏设置,这绝对是一个问题。

这个问题已经被讨论并解决了,方法是在UINavigationController委托中重新应用您的状态栏设置(请参见UIImagePickerController breaks status bar appearance)。

在您的情况下,您可能想要调用self.edgesForExtendedLayout = UIRectEdgeNone; 或尝试在委托回调中重置一些状态栏属性。

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

这是不正确的。第二张图片展示了模态页面表应该如何打开。 - Léo Natan
@LeoNatan 这是一个全屏模态页面。在iOS 7中,所有视图都应该在状态栏后面。请参见https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TransitionGuide/Bars.html。 - Jack
1
你有没有仔细阅读问题描述?问题只会在全屏模态视图控制器被解除后才出现。页面表单的布局存在错误。 - Léo Natan
1
@LeoNatan 对不起,我确实误读了问题,我会编辑我的答案。 - Jack
@JackWu,这个问题存在于所有以“页面”模式显示的模态视图控制器中。我能够在没有UIImagePickerController或UINavigationController的情况下重现它。 - Vitaly S.

-1

我认为这是iOS7的一个问题,其中视图的布局已经略有改变。 我曾经遇到过一个弹出式自定义视图的类似问题,我注意到了相同的行为。 我通过在viewDidLoad中添加这一行来解决它。

self.edgesForExtendedLayout = UIRectEdgeNone;

或许这对你的问题有一些提示作用。


对我不起作用 :( 你用这行代码修改了哪个视图控制器? - Vitaly S.
尝试将其放置在页面控制器内部,或者更确切地说,在您调用模态控制器的位置。 - gdm

-3

看起来这是一个iOS的bug,目前可以通过以下解决方法解决(这是“页面”模态视图控制器的一种方法)

#define STATUS_BAR_HEIGHT 20
#define IPAD_PORTRAIT_HEIGHT 1004
#define IPAD_LANDSCAPE_HEIGHT 748

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear: animated];

    // In case of iOS7 we need this weird code, because after displaying full screen view controller from 'Page' modal view controller our 'Page' controller
    // incorrectly shifts 20px up
    //
    // I haven't found best solution for now
    // There is my question on SO: https://dev59.com/hnvaa4cB1Zd3GeqPCFlF
    if (!isIOS6()) {
        [self setNeedsStatusBarAppearanceUpdate];

        UIView *superview = nil;

        // In case of this view controller included in navigationController we have to use superview of navigation's controller view
        if (self.navigationController)
            superview = self.navigationController.view.superview;
        else
            superview = self.view.superview;

        CGRect r = superview.frame;

        // Sometimes we have to fix height + origin, sometimes only height (becase view has bottom magnifying)
        // In landscape orientation we have to fix 'width' instead of 'height', because that view controller always works in 'portrait' mode
        if (self.interfaceOrientation == UIInterfaceOrientationPortrait && r.size.height > IPAD_PORTRAIT_HEIGHT) {
            r.origin.y = STATUS_BAR_HEIGHT;
            r.size.height = IPAD_PORTRAIT_HEIGHT;
        }
        else if (self.interfaceOrientation == UIInterfaceOrientationMaskPortraitUpsideDown && r.size.height > IPAD_PORTRAIT_HEIGHT) {
            r.size.height = IPAD_PORTRAIT_HEIGHT;
        }
        else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
            r.size.width = IPAD_LANDSCAPE_HEIGHT;
            r.origin.x = STATUS_BAR_HEIGHT;
        }
        else if (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight && r.size.width > IPAD_LANDSCAPE_HEIGHT) {
            r.size.width = IPAD_LANDSCAPE_HEIGHT;
        }

        superview.frame = r;
    }
}

投票反对这篇文章的人,有什么建议可以改进这个答案吗?我还没有找到另一个可行的解决方案。 - Vitaly S.

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