13

UIPresentationController用来显示底部提示。有时presentationController可能会出现另一个控制器。并且当呈现的控制器被解除时,presentationController 的高度发生了变化。那么为什么它会改变,我该如何解决这个问题。代码如下:

class ViewController: UIViewController {

    let presentVC = UIViewController()
    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let `self` = self else { return }
            self.presentBottom(self.presentVC)
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
            guard let `self` = self else { return }
            let VC = UIViewController()
            VC.view.backgroundColor = .red
            self.presentVC.present(VC, animated: true, completion: {

                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    VC.dismiss(animated: true, completion: nil)
                }

            })
        }
    }

}
public class PresentBottom: UIPresentationController {

    public override var frameOfPresentedViewInContainerView: CGRect {
        let bottomViewHeight: CGFloat = 200.0
        let screenBounds              = UIScreen.main.bounds
        return CGRect(x: 0, y: screenBounds.height - bottomViewHeight, width: screenBounds.width, height: bottomViewHeight)
    }

}
extension UIViewController: UIViewControllerTransitioningDelegate {

    public func presentBottom(_ vc: UIViewController ) {
        vc.view.backgroundColor = .purple
        vc.modalPresentationStyle = .custom
        vc.transitioningDelegate = self
        self.present(vc, animated: true, completion: nil)
    }

    public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        let vc = PresentBottom(presentedViewController: presented, presenting: presenting)
        return vc
    }
}

我的代码如下: 在此处输入图像描述

presentationController高度在下图中是正确的:

在此处输入图像描述

让我感到困惑的是,当前视图控制器的高度发生了变化:

在此处输入图像描述

4

1 回答 1

8

默认情况下,当呈现视图控制器时,UIKit 会在动画完成后移除呈现的 VC。呈现 VC 的视图只是在过渡期间临时添加到容器视图中。

在自定义演示文稿的情况下,您可以使用UIModalPresentationStyle.overFullScreen或使用shouldRemovePresentersView更改此行为。在这种情况下,只有呈现的视图被移动到临时视图,containerView并且所有动画都在呈现的 VC 视图之上执行 - 没有一个下面的视图被操纵。

在这里,您正在通过fullScreen自定义转换呈现的 VC 上方执行转换。UIKit 保持视图层次结构完整,仅在解除和演示转换期间将呈现 VC 的视图(紫色)与呈现的 VC 视图(红色)一起移动到容器视图。一旦动画完成,它就会删除紫色的。

didMoveToSuperview问题,显然(我在&方法中使用断点setFrame),当解除转换发生时,默认的“内置”动画控制器不关心当前 VC 视图的前一帧,当它临时将其添加到containerView. 在移动到containerView.

我不知道这是一个错误还是故意的选择。

这是我使用的代码:

class BottomVCView: UIView {
    override var frame: CGRect {
        set {
            super.frame = newValue // BREAKPOINT : newValue.height == 568.0
        }
        get {
            return super.frame
        }
    }
}

class BottomVC: UIViewController {

    lazy var myView = BottomVCView()

    override func loadView() {
        view = BottomVCView()
    }
}

这里是UIViewControllerBuiltinTransitionViewAnimator设置展示 VC 视图的框架的堆栈。

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000102ca0ce8 Project`BottomVCView.frame.setter(newValue=(origin = (x = 0, y = 0), size = (width = 320, height = 568)), self=0x00007ffde5e059f0) at ViewController.swift:35:13
    frame #1: 0x0000000102ca0c9f Project`@objc BottomVCView.frame.setter at <compiler-generated>:0
    frame #2: 0x0000000108e2004f UIKitCore`-[UIViewControllerBuiltinTransitionViewAnimator animateTransition:] + 1149
    frame #3: 0x0000000108d17985 UIKitCore`__56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 3088
    frame #4: 0x0000000109404cc9 UIKitCore`_runAfterCACommitDeferredBlocks + 318
    frame #5: 0x00000001093f4199 UIKitCore`_cleanUpAfterCAFlushAndRunDeferredBlocks + 358
    frame #6: 0x000000010942132b UIKitCore`_afterCACommitHandler + 124
    frame #7: 0x00000001056fe0f7 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    frame #8: 0x00000001056f85be CoreFoundation`__CFRunLoopDoObservers + 430
    frame #9: 0x00000001056f8c31 CoreFoundation`__CFRunLoopRun + 1505
    frame #10: 0x00000001056f8302 CoreFoundation`CFRunLoopRunSpecific + 626
    frame #11: 0x000000010d0dd2fe GraphicsServices`GSEventRunModal + 65
    frame #12: 0x00000001093f9ba2 UIKitCore`UIApplicationMain + 140
    frame #13: 0x0000000102ca60fb NavBar`main at AppDelegate.swift:12:7
    frame #14: 0x0000000106b9f541 libdyld.dylib`start + 1
    frame #15: 0x0000000106b9f541 libdyld.dylib`start + 1

如果您使用containerViewWillLayoutSubviews,您可以将紫色视图的框架设置回其正确值,但它只会在解除转换完成并且视图从fullScreen转换容器视图中移除后才会发生:

class PresentBottom: UIPresentationController {

    override func containerViewWillLayoutSubviews() {
        super.containerViewWillLayoutSubviews()
        presentedView?.frame = frameOfPresentedViewInContainerView
    }
}

我认为您可以简单地使用:

let VC = UIViewController()
VC.view.backgroundColor = .red
VC.modalPresentationStyle = .overFullScreen

保持所有视图层次结构。动画师不会触及呈现 VC 的视图 -viewController(for: .from)返回 nil,因为它的视图没有移动到容器视图。

于 2019-05-15T14:06:00.780 回答