当解散模态呈现的视图控制器时错误帧

问题描述:

我使用自定义转场和自定义UIPresentationController呈现UIViewController。视图控制器的视图不覆盖整个屏幕,因此呈现视图控制器仍然可见。当解散模态呈现的视图控制器时错误帧

接下来,我在此视图控制器的顶部呈现UIImagePickerController的实例。问题是,当我关闭图像选择器时,呈现视图控制器的框架覆盖整个屏幕,而不仅仅是我希望覆盖的部分。 frameOfPresentedViewInContainerView在我的自定义UIPresentationController中指定的框架似乎完全被忽略。

只有当图像采集器带有modalPresentationStyleUIModalPresentationOverCurrentContext我的框架保持不变(这是有道理的,因为没有视图首先从视图层次结构中删除)。不幸的是,这不是我想要的。我希望图像采集器能够全屏显示,无论出于何种原因,这似乎都会让我的布局变得糟糕。任何我可能在这里做错或忘记的事情?有什么建议么?

+1

也有类似的问题,但与'UIActivityViewController'只有当使用全屏幕共享,如邮件或邮件 –

这是预期的,因为全屏演示文稿不会恢复由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返回包装视图,而不是默认值 - 呈现视图控制器的看法。这样,即使第二个演示文稿修改了包装器的框架,所呈现的视图控制器的视图也不会改变。

+3

感谢您的建议@erudel但不幸的是这并没有解决我的问题。我从中得到的结果是,自定义的视图控制器在**视图控制器的解除动画之后是正确的**这是我以前通过简单地重新调整所呈现的视图控制器的框架而实现的效果在'containerViewWillLayoutSubviews'中查看(不需要包装视图)。 **然而,在**解雇动画期间,视图的框架保持全屏,这导致布局改变跳跃,并且首先当然不正确。 – caryot

+1

'containerViewWillLayoutSubviews'处理旋转或自适应等绑定更改,但需要使用包装视图以避免在关闭全屏演示文稿时出现“跳跃”。 – erudel

+0

事情是我按照你提出的方式实现它,但我仍然得到了跳跃@erudel。 – caryot

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。

+0

仍然介意这样做。 –

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

尝试将提供的UIImagePickerControllermodalPresentationStyle设置为UIModalPresentationOverFullScreen,而不是执行包装技巧。这意味着图像选择器下方的视图将不会在呈现/解散期间从视图层次结构中移除/恢复。

+0

这是好得多 - 更少的黑客,更有保证长期工作 –

+0

圣牛... 。我在每一个硬表面上都猛敲我的脑袋,试图弄明白这一点。从来没有人会想到这是一个简单的解决方案。非常感谢!:)顺便说一句,这应该是公认的答案。 – Annjawn

这个工作对我来说,在UIPresentationController

override func containerViewWillLayoutSubviews() { 

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

这对我来说是正确的解决方案。 – Kie

我试图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 
     } 
    }