解除模态显示的视图控制器

时间:2016-06-21 16:17:51

标签: ios objective-c uiviewcontroller presentviewcontroller uipresentationcontroller

我使用自定义转换和自定义UIViewController呈现UIPresentationController。视图控制器的视图不会覆盖整个屏幕,因此呈现视图控制器仍然可见。

接下来,我在此视图控制器的顶部显示UIImagePickerController的实例。问题是,当我关闭图像选择器时,呈现视图控制器的框架覆盖整个屏幕而不是我想要它覆盖的部分。 <{1}}在我的自定义frameOfPresentedViewInContainerView中指定的框架似乎完全被忽略了。

仅当存在UIPresentationController modalPresentationStyle UIModalPresentationOverCurrentContext我的帧的图像选择器保持不变时(这是有意义的,因为首先不会从视图层次结构中删除视图)。不幸的是,这不是我想要的。我希望图像选择器全屏显示,无论出于何种原因,它似乎搞乱了我的布局。我可能做错了什么或遗忘在这里?有什么建议吗?

5 个答案:

答案 0 :(得分:14)

我尝试了两种提到的包装方法。使用这种包装方法的一个副作用是设备旋转不能很好地显示 - 在呈现的视图周围引入黑框。

尝试将呈现的modalPresentationStyle的{​​{1}}设置为UIImagePickerController,而不是执行换行技巧。这意味着在呈现/解雇期间,图像选择器下面的视图不会从视图层次结构中删除/恢复。

答案 1 :(得分:4)

这是预期的,因为全屏演示文稿不会恢复由frameOfPresentedViewInContainerView计算的原始帧。 修复此问题的推荐方法是创建一个包装器视图,您将在其中插入显示的视图控制器视图。以下是自定义演示控制器的相关代码:

- (void)presentationTransitionWillBegin {
    // wrapper is a property defined in the custom presentation controller.
    self.wrapper = [UIView new];
    [self.wrapper addSubview:self.presentedViewController.view];
}

- (CGRect)frameOfPresentedViewInContainerView {
    CGRect result = self.containerView.frame;

    // In this example we are doing a half-modal presentation
    CGFloat height = result.size.height/2;
    result.origin.y = height;
    result.size.height = height;

    return result;
}

- (UIView *)presentedView {
    return self.wrapper;
}

- (BOOL)shouldPresentInFullscreen {
    return NO;
}

- (void)containerViewWillLayoutSubviews {
    self.wrapper.frame = self.containerView.frame;
    self.presentedViewController.view.frame = [self frameOfPresentedViewInContainerView];
}

请注意,我们覆盖presentedView以返回包装器视图而不是默认值 - 呈现的视图控制器视图。这样,即使第二个表示修改了包装器的帧,呈现的视图控制器的视图也不会改变。

答案 2 :(得分:2)

erudel's solution不能按原样为我工作,但在wrapperViewpresentedViewController.view之间添加另一个视图可以解决问题(我不明白为什么):

- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController
                       presentingViewController:(UIViewController *)presentingViewController {
    if (self = [super initWithPresentedViewController:presentedViewController
                             presentingViewController:presentingViewController]) {
        _wrapperView = [[UIView alloc] init];
        _wrapperView2 = [[UIView alloc] init]; // <- new view
    }
    return self;
}

- (CGRect)frameOfPresentedViewInContainerView {
    return self.containerView.bounds;
}

- (UIView *)presentedView {
    return self.wrapperView;
}

- (BOOL)shouldPresentInFullscreen {
    return NO;
}

- (void)containerViewWillLayoutSubviews {
    self.wrapperView.frame = self.containerView.frame;
    self.wrapperView2.frame = /* your custom frame goes here */;
    self.presentedViewController.view.frame = self.wrapperView2.bounds;
}

- (void)presentationTransitionWillBegin {
    [self.wrapperView addSubview:self.wrapperView2];
    [self.wrapperView2 addSubview:self.presentedViewController.view];

    // Set up a dimming view, etc
}

在iOS 9.3上测试过。

答案 3 :(得分:1)

这对我有用UIPresentationController

override func containerViewWillLayoutSubviews() {

     super.containerViewWillLayoutSubviews()
     presentedViewController.view.frame = frameOfPresentedViewInContainerView
}

答案 4 :(得分:1)

我尝试了containerViewWillLayoutSubviews,但它并不是很有效。如果可能的话,我想避免额外的包装器视图。我想出了使用presentedView修正视图框架的策略。此外,我能够删除containerViewWillLayoutSubviewsforceFrame已针对我们的特定用例进行了调整。 presentedFrame由我们的自定义动画师设置。

class CustomModalPresentationController: UIPresentationController {

        var presentedFrame = CGRect.zero
        var forceFrame = false

        override func dismissalTransitionWillBegin() {
            forceFrame = false
        }
        override func presentationTransitionDidEnd(_ completed: Bool) {
            forceFrame = true
        }
        override var presentedView: UIView? {
            if forceFrame {
                presentedViewController.view.frame = presentedFrame
            }
            return presentedViewController.view
        }
        override var frameOfPresentedViewInContainerView: CGRect {
            return presentedFrame
        }
    }