【问题标题】:Disable the interactive dismissal of presented view controller禁用呈现的视图控制器的交互式解除
【发布时间】:2019-10-20 21:29:46
【问题描述】:

iOS 13 为模态呈现的视图控制器引入了modalPresentationStyle .pageSheet(及其兄弟.formSheet)的新设计……

...我们可以通过向下滑动呈现的视图控制器来关闭这些工作表(交互式关闭)。尽管新的“pull-to-dismiss”功能非常有用,但它可能并不总是可取的。

问题:我们如何关闭交互式解雇? - 请记住,我们保持演示风格相同。

【问题讨论】:

标签: ios uiviewcontroller uikit modalviewcontroller ios13


【解决方案1】:

所有解决方案都很好,但就我而言,我需要一个停止移动的选项。 所以这是一个代码。

如果你想阻止移动:

self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = false

如果你想解锁移动:

self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = true

【讨论】:

    【解决方案2】:

    如果你有一些业务逻辑,比如所有字段都应该在关闭之前填写,你应该:

    ViewDidLoad 上,如果您的 ViewController 已经出现在导航控制器中:

    func viewDidLoad() { 
        self.navigationController?.presentationController?.delegate = self
    }
    

    如果没有,只需使用

    func viewDidLoad() { 
        self.presentationController?.delegate = self
    }
    

    然后实现委托方法:

    extension ViewController: UIAdaptivePresentationControllerDelegate {
    
        func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
            guard let text = firstName.text, text.isEmpty else { return false }
            guard let text = lastName.text, text.isEmpty else { return false }
            ...
        
            return true
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      您现在可以实现交互手势识别器的委托,并在尝试同时与滑块交互时禁用交互。这样,您可以保持交互式关闭,而滑块按预期工作。

      您可以像这样禁用向下滑动:

      let controller = storyboard?.instantiateViewController(withIdentifier: "NextVC") as! NextVC
      let navigationController = UINavigationController(rootViewController: controller)
      self.present(navigationController, animated: true, completion: {
         navigationController.presentationController?.presentedView?.gestureRecognizers?[0].isEnabled = false
      })
      

      【讨论】:

      • 这帮助我实现了想要的效果。我希望演示控制器呈现为.pagesheet,但是当在呈现的控制器中进行捏合缩放时,我想禁用关闭手势(并在完成捏合时重新启用)。 isModalInPresentation 几乎成功了,但视图仍然反弹,这很烦人。
      【解决方案4】:

      Apple 分享了一个关于它的示例代码at this link

      它使用isModalInPresentation 尽可能多的用户建议。

      【讨论】:

        【解决方案5】:

        选项 1:

        viewController.isModalInPresentation = true
        

        (禁用互动 .pageSheet 解雇行为是这样的。)

        • 从 iOS 13 开始,UIViewController 包含一个名为 isModalInPresentation 的新属性,必须将其设置为 true 以防止交互式解除。
        • 它基本上会忽略视图控制器范围之外的事件。请记住,如果您不仅使用自动样式,还使用 ​​.popover 等演示样式。
        • 此属性默认为false

        来自official docs:如果是true,UIKit 会忽略视图控制器范围之外的事件,并阻止视图控制器在屏幕上的交互解除。


        选项 2:

        func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
            return false
        }
        
        • 从 iOS 13 开始,UIAdaptivePresentationControllerDelegate 包含一个名为 presentationControllerShouldDismiss 的新方法。
        • 仅当呈现的视图控制器未以编程方式关闭且其isModalInPresentation 属性设置为false 时才调用此方法。

        提示:不要忘记分配presentationController的委托。

        【讨论】:

        • 如果显示的视图控制器是导航控制器,您可以在导航控制器或导航堆栈中显示的单个视图控制器上设置isModalInPresentation。后者允许您逐个屏幕选择是否可以进行交互式解除。小心搜索控制器,它们优先于单个视图控制器(但不是导航控制器)。更多信息在我的博文中:medium.com/@hacknicity/…
        • 请记住,如果您的 VC 显示为弹出框,这将防止弹出框在其外部点击时被关闭
        • Objective-C: viewController.modalInPresentation = YES;
        • UIImagePickerController 上设置此标志时,任何人都可以使用它吗?对我们来说,UIImagePickerController 似乎忽略了它,因此可以通过滑动手势将其关闭。可能是 iOS 13 的错误。
        • presentationControllerShouldDismiss(_ presentationController: UIPresentationController) 返回false 时,会调用presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController),这样您就可以在用户输入数据时添加确认对话框等操作。
        【解决方案6】:

        如果您使用故事板来布局您的 UI,我发现在使用导航控制器时禁用此交互式关闭的最佳方法是将属性检查器中导航控制器的显示从自动更改为全屏。导航堆栈中的所有视图控制器都将全屏显示,并且无法被用户关闭。

        Attribute Inspector showing presentation option for the navigation controller

        【讨论】:

          【解决方案7】:

          isModalInPresentation 属性可能会有所帮助。

          来自文档:

          当您将其设置为true 时,UIKit 会忽略视图控制器范围之外的事件,并防止视图控制器在屏幕上时以交互方式关闭。

          你可以这样使用它:

          let controller = MyViewController()
          controller.isModalInPresentation = true
          self.present(controller, animated: true, completion: nil)
          

          【讨论】:

            【解决方案8】:
            1. 如果您想要与以前的 iOS 版本 (UIModalPresentationStyle.fullScreen

              let someViewController = \*VIEW CONTROLLER*\
              someViewController.modalPresentationStyle = .fullScreen
              

              如果您使用情节提要,只需选择 segua 并从 Presentation 下拉列表中选择 Full Screen

            2. 如果您只想禁用交互式解除并保持新的演示样式设置UIViewController 属性isModalInPresentationtrue

              if #available(iOS 13.0, *) {
                  someViewController.isModalInPresentation = true // available in IOS13
              }
              

            【讨论】:

            • 它比使用 {controller.isModalInPresentation = true } 效果更好。
            最近更新 更多