实现自定义视图控制器演示时,应用呈现视图的约束的位置?

bso*_*sod 16 objective-c ios autolayout swift

我已经阅读了Apple关于自定义模式演示文稿的所有文档,但我找不到这个答案.当使用自定义动画呈现视图控制器时,我们可以返回3个内容(如果转换不是交互式的,交互式可以返回4个):呈现控制器和两个动画控制器(一个用于存在,一个用于解除).

在演示控制器和当前动画控制器中,Apple的代码都不包含约束.关于框架的讨论范围是Apple建议在当前动画控制器中设置所呈现的视图控制器视图的框架(如下):

// Always add the "to" view to the container.
// And it doesn't hurt to set its start frame.
[containerView addSubview:toView];
toView.frame = toViewStartFrame;
Run Code Online (Sandbox Code Playgroud)

......就是这样.

我遇到的问题是模拟器(以及我拥有的设备)中的这些呈现的视图控制器无法识别双高状态栏.更确切地说,没有一种解决方案适用于所有模拟器 - 在新模拟器(如iPhone 8)中工作的解决方案在旧的模拟器(如iPhone 5)中不起作用.如果我让Apple使用默认的UIKit动画来处理演示文稿,则所呈现的视图控制器可以很好地处理双高状态栏.因此,我可以假设所呈现的视图控制器中的约束不是问题.

所以我转向演示控制器containerViewDidLayoutSubviewscontainerViewWillLayoutSubviews方法,没有任何运气:

override func containerViewDidLayoutSubviews() {
    super.containerViewDidLayoutSubviews()
    presentedViewController.view.frame = containerView!.bounds
}
Run Code Online (Sandbox Code Playgroud)

上面的代码仅在第一次引入双高状态栏时才在模拟器中工作; 从那以后,这种方法变得反应迟钝.要验证这一点:

override func containerViewDidLayoutSubviews() {
    super.containerViewDidLayoutSubviews()
    presentedViewController.view.frame = containerView!.bounds
    print("did layout")
}
Run Code Online (Sandbox Code Playgroud)

在首次引入双高状态栏后,上述方法停止打印到控制台.但是,如果我将任务更改为不会改变所呈现视图框架大小的内容,例如更改其背景颜色:

override func containerViewDidLayoutSubviews() {
    super.containerViewDidLayoutSubviews()
    presentedViewController.view.backgroundColor = UIColor.blue
    print("did layout")
}
Run Code Online (Sandbox Code Playgroud)

方法永远不会破坏.无论出于何种原因,在此方法中更改显示的视图框架的大小会在双高度状态栏的第一个切换之后中断该方法.我很想解释这种行为.不太可能是一个bug,但看起来像一个.

无论如何,Apple说如果正确使用自动布局,程序员就什么都不做!所以我的问题是,我们应该在何处或如何给出所呈现的视图控制器的视图约束,以便它可以适应其临时容器?因为,IMO,那就是问题所在.呈现的视图控制器由转换的容器视图拥有,该视图是由UIKit提供的临时视图,我们没有太多的主导权.如果我们可以将呈现的视图锚定到该容器,则所有问题都将得到解决.但我从未见过苹果这样做,甚至没有谈过这个.

注:显式锚定所呈现的视图到所述容器的任何地方视图 - 在本动画控制器(动画其完成处理程序之前或在)中,在呈现控制器,或在自适应委托方法 - 如所提到的不产生一致的结果早.

结论:(1)无法通过模态演示正式,正确,干净或一致地处理双高状态栏; (2)Apple使用双倍高度状态栏对其进行了拙劣,并且不能等到所有iPhone在屏幕上都有缺口的那一天.

few*_*ode 6

我的回答是:在自定义模态演示的情况下,您不应该使用约束

因此,我知道你的痛苦,所以我会尝试通过提供一些我突然透露的提示来帮助你节省时间和精力.


示例案例:

卡片UI动画如下:

在此输入图像描述

进一步使用条款:

  • - UIViewController使用"详细信息"栏按钮项
  • 孩子 - UIViewController与"另一个"

你提到的麻烦开始了,当我的动画涉及尺寸随着运动而变化时.它会产生不同的影响,包括:

  • 父母的状态不足区域出现并消失
  • 家长的子视图动画效果不佳 - 跳跃,重复和其他故障.

经过几天的调试和搜索,我想出了以下解决方案(对不起一些神奇的数字;)):

UIView.animate(withDuration: transitionDuration(using: transitionContext),
                       delay: 0,
                       usingSpringWithDamping: 1,
                       initialSpringVelocity: 0.4,
                       options: .curveEaseIn, animations: {
            toVC.view.transform = CGAffineTransform(translationX: 0, y: self.finalFrame.minY)
            toVC.view.frame = self.finalFrame
            toVC.view.layer.cornerRadius = self.cornerRadius

            fromVC.view.layer.cornerRadius = self.cornerRadius
            var transform = CATransform3DIdentity
            transform = CATransform3DScale(transform, scale, scale, 1.0)
            transform = CATransform3DTranslate(transform, 0, wdiff, 0)
            fromVC.view.layer.transform = transform
            fromVC.view.alpha = 0.6
        }) { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
Run Code Online (Sandbox Code Playgroud)

这里的要点是,你必须使用它CGAffineTransform3D来避免动画问题和子视图动画的问题(2D变换不能用于未知的原因).

我希望这种方法可以在不使用约束的情况下修复所有问题.

随意问的问题.

UPD:根据In-Call状态栏

之后的所有可能的实验小时,检查类似的项目像这个这个和类似计算器的问题这样,(它实际上乐趣,有机磷农药的回答是有)和类似的,我完全糊涂了.好像我的解决方案处理UIKit级别的双状态栏(它正确调整),但同样的运动忽略了以前的转换.原因不明.


代码示例:

您可以在Github上看到工作解决方案

PS我不确定是否可以在答案中发布GitHub链接.我很感激建议如何在答案中发布100-300行代码.