我使用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
的高度正好在下图中:
让我感到困惑的是,当前视图控制器的高度已更改:
答案 0 :(得分:6)
默认情况下,当呈现视图控制器时,UIKit会在动画完成后删除呈现的VC。呈现的VC的视图只是在过渡期间临时添加到容器视图中。
对于自定义演示,您可以使用UIModalPresentationStyle.overFullScreen
或shouldRemovePresentersView来更改此行为。在这种情况下,仅将呈现的视图移动到临时containerView
,并且所有动画均在呈现的VC的视图上方执行-不会操纵任何下面的视图。
在这里,您正在由自定义过渡呈现的VC之上执行fullScreen
过渡。 UIKit保持视图层次结构不变,并且在解雇和表示过渡期间,仅将呈现的VC的视图(紫色的视图)与呈现的VC的视图(红色的视图)一起移动到容器视图。动画制作完成后,它将删除紫色的一个。
问题很明显(我在didMoveToSuperview
和setFrame
方法中使用了断点),当发生解雇过渡时,默认的“内置”动画控制器并不关心前一帧当前的VC视图临时添加到containerView
中时。移至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
过渡containerView中移除后,紫色视图才会出现:
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,因为其视图未移至容器视图。