iPad / iOS7:'页面'模式视图控制器奇怪的行为后,从它呈现'全屏'视图控制器

时间:2014-01-15 19:46:33

标签: ios ipad ios7

我的iPad应用程序打开带有“页面”演示风格的模态视图控制器。如您所知,“页面”演示文稿样式不包括呈现视图控制器以指示页面显示的状态栏。

Initial view controller

Page modal view controller

在模态视图控制器中,应用会打开UIImagePickerController来制作照片。 UIImagePickerController具有“全屏”演示风格。解散图像选择器呈现模态视图控制器变为20px更高并重叠初始视图控制器的状态栏。

我尝试用简单UIImagePickerController替换UINavigationController,它也会破坏我的模态视图控制器。

有屏幕截图: Full screen view controller

Broken modal view controller

他们只能恢复'Page'视图控制器的大小,在返回'Page'视图控制器后改变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;

我不相信没有更优雅的解决方案。任何想法如何改进它?

UPDATE2:我刚刚开了个bug。您可以在那里关注:rdar://15949644

UPDATE3:我的示例项目有:link

5 个答案:

答案 0 :(得分:2)

没有好的解决方案,它是一个Apple漏洞,在修复之前,你必须解决它。它尚未在iOS 7.1中修复。我致力于解决这个问题,并意识到我也在实施相同的解决方案。这很难看,但它确实有效。

关于此设计的一句话。我猜想Apple为什么忽略这个问题是因为在全屏幕上呈现一个视图控制器并不是Apple会做的事情。这当然不是一个借口,有时除了提供全屏之外别无选择(我们必须打开一个摄像机视图,例如必须以全屏方式打开)。也许你可以改变你的设计以适应Apple的错误。

答案 1 :(得分:1)

“确保呈现模态视图的ViewController在NavigationController中,这种怪异应该停止。”我最初的回答 - 错误

<强>更新 这确实听起来像一个错误,虽然从用户体验的角度来看,你不应该真正击中它。呈现处于“页面”呈现样式的视图控制器然后以全屏模式呈现另一个视图控制器似乎有点不对。

IMO从一开始就是糟糕的设计,所以事实上它并没有像你期望的那样行事,因为无论是谁设置它都没有预料到会有人像这样使用它。

我会,就像我最初的回答所说的那样,简单地说,将你的模态呈现的视图控制器嵌入到导航控制器中并将UIImagPickerViewController推入其中,或者将它的动画视图添加到你的视图中,好像它似乎表现得像另一个页面样式模态视图。如果那是你想要的影响。

这一切听起来都不完美,更完美的解决方案是查看你应用程序的流程,或者重新评估事物的呈现方式。

答案 2 :(得分:-1)

我认为这是iOS7的一个问题,其中View的布局略有改变。 我有一个类似于pop模式自定义View的问题,我注意到了同样的行为。 我通过在viewDidLoad

中添加此行来解决
self.edgesForExtendedLayout = UIRectEdgeNone;

也许这对你的问题提示有用。

答案 3 :(得分:-1)

UIImagePicker(或者更广泛地说,UINavigationController)肯定存在问题,它不遵守应用程序中的任何状态栏设置。

通过在UINavigationController委托中重新应用状态栏设置已经讨论并解决了这个问题(参见UIImagePickerController breaks status bar appearance)。

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

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

答案 4 :(得分:-3)

看起来这是一个iOS错误,现在它可以通过这种解决方法解决(它是'Page'模态视图控制器的方法)

#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: http://stackoverflow.com/questions/21146801/ipad-ios7-page-modal-view-controller-strange-behaviour-after-presenting-full
    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;
    }
}