现在,iOS 13默认将视图控制器呈现为一个卡片,这意味着该卡片将部分覆盖底层视图控制器,也就是说,viewDidAppear不会被调用,因为父视图控制器实际上从未消失。
有没有一种方法可以检测到已解除显示的视图控制器表格?我可以在父视图控制器中覆盖另一个函数,而不是使用某种代理吗?
presentation controller did dismiss
不会被调用。 - Irina下面是一个父视图控制器的代码示例,当它呈现的子视图控制器以 模式窗口(即在默认的iOS 13方式中)被解除时,父视图控制器会收到通知:
这里是一个父级视图控制器的代码示例,当它呈现的子视图控制器以表单形式(即在默认的iOS 13方式中)被关闭时,会向父视图控制器发送通知:
public final class Parent: UIViewController, UIAdaptivePresentationControllerDelegate
{
// This is assuming that the segue is a storyboard segue;
// if you're manually presenting, just set the delegate there.
public override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "mySegue" {
segue.destination.presentationController?.delegate = self;
}
}
public func presentationControllerDidDismiss(
_ presentationController: UIPresentationController)
{
// Only called when the sheet is dismissed by DRAGGING.
// You'll need something extra if you call .dismiss() on the child.
// (I found that overriding dismiss in the child and calling
// presentationController.delegate?.presentationControllerDidDismiss
// works well).
}
}
Jerland2的回答有些混淆,因为(a)原问题提出者想要在表单被解散时调用函数(而他实现了presentationControllerDidAttemptToDismiss,这个函数是在用户尝试但失败地关闭表单时调用的),以及(b)设置isModalInPresentation完全正交,事实上会使呈现的表单无法关闭(这与OP的愿望相反)。
以下是更完整的答案和实现方式,供后来者参考:
// Modal Dismiss iOS 13
modalNavController.presentationController?.delegate = modalVc
// MARK: - iOS 13 Modal (Swipe to Dismiss)
extension ModalViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
print("slide to dismiss stopped")
self.dismiss(animated: true, completion: nil)
}
}
确保在模态视图控制器中,以下属性为true,以便调用委托方法。 self.isModalInPresentation = true
presentationControllerDidDismiss
应该可以解决问题。 - gondopresentationControllerDidAttemptToDismiss
是用于当用户试图以编程方式阻止时(仔细阅读该方法的文档)而预期的情况。presentationControllerWillDismiss
方法用于检测用户打算解除OR presentationControllerShouldDismiss
来控制解除OR presentationControllerDidDismiss
来检测已被解除的事实。 - Vitalii另一个获取 viewWillAppear
和 viewDidAppear
的选项是设置
let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen
这个选项可以覆盖整个屏幕,关闭后会调用上述方法。
如果您希望在用户从模态表单中关闭时执行某些操作,假设您已经拥有一个带有 @IBAction
的关闭按钮,并且具有在关闭之前显示警告或执行其他操作的逻辑。您只需要检测到用户何时按下此控制器。
方法如下:
class MyModalSheetViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.presentationController?.delegate = self
}
@IBAction func closeAction(_ sender: Any) {
// your logic to decide to close or not, when to close, etc.
}
}
extension MyModalSheetViewController: UIAdaptivePresentationControllerDelegate {
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false // <-prevents the modal sheet from being closed
}
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
closeAction(self) // <- called after the modal sheet was prevented from being closed and leads to your own logic
}
}
self.navigationController?.presentationController?.delegate = self
。 - Oluwatobi OmotayoSwift
iOS13中调用viewWillAppear
的通用解决方案
class ViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear")
}
//Show new viewController
@IBAction func show(_ sender: Any) {
let newViewController = NewViewController()
//set delegate of UIAdaptivePresentationControllerDelegate to self
newViewController.presentationController?.delegate = self
present(newViewController, animated: true, completion: nil)
}
}
extension UIViewController: UIAdaptivePresentationControllerDelegate {
public func presentationControllerDidDismiss( _ presentationController: UIPresentationController) {
if #available(iOS 13, *) {
//Call viewWillAppear only in iOS 13
viewWillAppear(true)
}
}
}
dismiss(_)
来关闭窗口。 - Pedro Paulo Amorim重写即将消失的UIViewController
上的viewWillDisappear
方法。通过isBeingDismissed
布尔标志,它将提醒您该视图控制器正在被消除。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isBeingDismissed {
print("user is dismissing the vc")
}
}
如果用户在向下滑动时只完成一半的距离,然后将卡片向上滑回去,即使未将该卡片解除,也会被注册为已解除。但这是一个边界情况,您可能不太关心。
self.dismiss(animated: Bool, completion: (() -> Void)?)
是什么意思? - iGhostself.dismiss(animated: Bool, completion: (() -> Void)?)
不会检测到解除显示。相反,它将导致一个操作发生,然后您可以在其上进行一些工作。使用 viewWillDisappear
将监听解除显示的事件。 - craft拖拽或调用DISMISS函数将使用以下代码:
1)在根视图控制器中,您可以通过以下代码指定其表示视图控制器:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "presenterID" {
let navigationController = segue.destination as! UINavigationController
if #available(iOS 13.0, *) {
let controller = navigationController.topViewController as! presentationviewcontroller
// Modal Dismiss iOS 13
controller.presentationController?.delegate = self
} else {
// Fallback on earlier versions
}
navigationController.presentationController?.delegate = self
}
}
2) 再次在根视图控制器中,您告诉它的呈现视图控制器被解除时会发生什么
public func presentationControllerDidDismiss(
_ presentationController: UIPresentationController)
{
print("presentationControllerDidDismiss")
}
1) 在演示视图控制器中,当您点击此图片中的取消或保存按钮时,将调用以下代码。
self.dismiss(animated: true) {
self.presentationController?.delegate?.presentationControllerDidDismiss?(self.presentationController!)
}
func sheet<Item, Content>(item: Binding<Item?>, onDismiss: (() -> Void)?, content: (Item) -> Content) -> some View
modalPresentationStyle
更改为 fullScreen
或者使用上述方法之一添加策略。 override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
if let _ = viewControllerToPresent as? TargetVC {
viewControllerToPresent.modalPresentationStyle = .fullScreen
}
super.present(viewControllerToPresent, animated: flag, completion: completion)
}
如果呈现的视图控制器是导航控制器,你想检查根控制器,可以将上面的条件更改为如下:
if let _ = (viewControllerToPresent as? UINavigationController)?.viewControllers.first as? TargetVC {
viewControllerToPresent.modalPresentationStyle = .fullScreen
}