检测表已在iOS 13上关闭

Mar*_*aka 41 uiviewcontroller uikit ios swift ios13

在iOS 13之前,提供了用于覆盖整个屏幕的视图控制器。并且,在关闭后,将viewDidAppear执行父视图控制器功能。

现在,iOS 13默认将表单显示为视图控制器,这意味着卡将部分覆盖基础视图控制器,这意味着viewDidAppear不会被调用,因为父视图控制器从未真正消失过。

有没有一种方法可以检测到所显示的视图控制器工作表已被解雇?我可以在父视图控制器中重写某些其他功能,而不是使用某种委托

mat*_*att 20

有没有一种方法可以检测到所显示的视图控制器工作表已被解雇?

是。

我可以在父视图控制器中重写某些其他功能,而不是使用某种委托?

不,“某种委托”是您的工作方式。使自己成为演示控制器的委托和重写presentationControllerDidDismiss(_:)

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229889-presentationcontrollerdiddismiss


缺少一个一般的运行时生成的事件,通知您所显示的视图控制器(无论是否为全屏)已被关闭,这确实很麻烦。但这不是一个新问题,因为始终存在非全屏显示的视图控制器。只是现在(在iOS 13中)有更多!我在其他地方对此主题进行了单独的问答:统一UIViewController“成为最前面的”检测工具?

  • @matt 感谢您的回答。当以编程方式关闭视图时,不会调用该视图(正如伊琳娜所说),而且您是对的,我们知道我们做到了。我只是认为,为了在 iOS13 中获得一种具有新模式呈现样式的“viewWillAppear”,需要编写大量不必要的样板代码。当您通过提取路由的架构(例如在 MVVM + 协调器中,或 VIPER 中的路由器类型)管理路由时,它会变得特别混乱。 (9认同)
  • @Irina,您好-如果您以编程方式关闭视图,则不需要回调,因为您已以编程方式关闭视图-您_知道_是您这样做的,因为_you_是这样做的。只有在_user_这样做的情况下,委托方法才可以。 (4认同)
  • @AdamWaite 我同意,但这个问题并不新鲜。多年来我们一直遇到这个问题,包括弹出窗口、非全屏呈现的视图控制器、警报等等。我认为这是苹果“事件”库中的一个严重缺陷。我只是说现实是什么以及为什么。我在这里直接解决这个问题:/sf/ask/3822186371/ (4认同)
  • 这还不够。如果呈现的VC中有一个nabber,并且有一个以编程方式关闭视图的自定义条形按钮,则不会调用presentation controller的关闭。 (2认同)

Pit*_*Pan 17

另一个取回viewWillAppearviewDidAppear设置的选项

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen
Run Code Online (Sandbox Code Playgroud)

此选项全屏显示,关闭后调用上述方法

  • 这是一种解决方法,而不是解决方法。所有人都回到iOS 12样式表并不是很好。iOS 13很棒!:) (3认同)
  • 谢谢PiterPan。可以了 这是很好且最快的解决方案。 (2认同)

Mat*_*att 14

这是父视图控制器的代码示例,该子视图在子视图控制器呈现为工作表时(即,以默认的iOS 13方式)被通知时通知:

public final class Parent: UIViewController, UIAdaptivePresentationControllerDelegate
{
  // This is assuming that the segue is a storyboard segue; 
  // if you're manually presenting, just see 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).
  }
}
Run Code Online (Sandbox Code Playgroud)

Jerland2的答案很混乱,因为(a)最初的提问者想在关闭工作表时获得一个函数调用(而他实现了presentationControllerDidAttemptToDismiss,当用户尝试并无法关闭工作表时会调用它),并且(b)设置isModalInPresentation是完全正交的,实际上会使所呈现的图纸不可忽略(这与OP想要的相反)。

  • 这很好。提示:如果在被调用的VC上使用导航控制器,则应将导航控制器分配为presentationController?,delegate(而不是将导航所具有的VC作为topViewController)。 (2认同)

Vit*_*lii 10

如果您想在用户从该工作表中关闭模式工作表时执行某些操作。假设您已经有一些“关闭”按钮,其中包含一个@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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您的模态视图控制器嵌入在导航控制器中,您可能必须调用 self.navigationController?.presentationController?.delegate = self` (4认同)

Jer*_*nd2 8

For future readers here is a more complete answer with implementation:

  1. In the root view controllers prepare for segue add the following (Assuming your modal has a nav controller)
    // Modal Dismiss iOS 13
    modalNavController.presentationController?.delegate = modalVc
Run Code Online (Sandbox Code Playgroud)
  1. In the modal view controller add the following delegate + method
// 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)
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. Ensure in the modal View Controller that the following property is true in order for the delegate method to be called
    self.isModalInPresentation = true
Run Code Online (Sandbox Code Playgroud)
  1. Profit

  • self.isModalInPresentation = true 那么拖动关闭不起作用。删除该行委托方法仍然可以调用。谢谢。 (2认同)
  • 这是令人困惑的,因为(a)原始提问者希望在关闭工作表时获得函数调用(而您已经实现了presentationControllerDidAttemptToDismiss,当用户尝试关闭工作表但失败时调用该函数),以及(b)设置 isModalInPresentation是完全正交的,事实上将使所呈现的工作表不可驳回(这与OP想要的相反)。 (2认同)

cra*_*aft 7

覆盖正在被驳回的viewWillDisappear内容UIViewController。它会通过布尔标志提醒您解雇isBeingDismissed

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if isBeingDismissed {
        print("user is dismissing the vc")
    }
}
Run Code Online (Sandbox Code Playgroud)

** 如果用户向下滑动一半并向上滑动卡片,即使卡片没有被关闭,它仍然会注册为被关闭。但这是您可能不关心的极端情况。


dim*_*mdy 6

迅速

viewWillAppeariOS13 中调用的一般解决方案

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)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这仅使用从顶部滑动来处理解雇,而不是通过调用函数“解雇(_)”。 (2认同)