禁用呈现视图控制器的交互式解雇
Disable the interactive dismissal of presented view controller
iOS 13 引入了 modalPresentationStyle
.pageSheet
(及其兄弟 .formSheet
)的新设计,用于模态呈现视图控制器…
…我们可以通过向下滑动呈现的视图控制器来关闭这些工作表(交互式关闭)。尽管新的 "pull-to-dismiss" 功能非常有用,但它可能并不总是令人满意的。
问题:我们怎样才能关闭交互式关闭?
- 请记住,我们保持相同的演示风格。
选项 1:
viewController.isModalInPresentation = true
(禁用交互.pageSheet
解雇行为。)
- 由于 iOS 13,
UIViewController
包含一个名为 isModalInPresentation
的新 属性,必须将其设置为 true
以防止交互解雇。
- 它基本上忽略了视图控制器范围之外的事件。如果您不仅使用自动样式,还使用
.popover
等演示样式,请记住这一点。
- 这个属性默认是
false
。
From the official docs: If true
, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.
选项 2:
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false
}
- 由于 iOS 13,
UIAdaptivePresentationControllerDelegate
包含一个名为 presentationControllerShouldDismiss
的新方法。
- 仅当呈现的视图控制器未以编程方式关闭且其
isModalInPresentation
属性 设置为 false
时才会调用此方法。
Tip: Don't forget to assign presentationController's delegate.
如果您想要与以前的 iOS 版本 (< iOS13) 相同的行为,例如全屏模型演示,只需设置目标视图的演示样式控制器到 UIModalPresentationStyle.fullScreen
let someViewController = \*VIEW CONTROLLER*\
someViewController.modalPresentationStyle = .fullScreen
如果您正在使用故事板,只需 select segua 和 select Full Screen
形成 Presentation
下拉列表。
如果您只想禁用交互式解雇并保持新的演示文稿样式,请将 UIViewController
属性 isModalInPresentation
设置为 true
。
if #available(iOS 13.0, *) {
someViewController.isModalInPresentation = true // available in IOS13
}
属性 isModalInPresentation
可能会有帮助。
来自文档:
When you set it to true
, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.
你可以这样使用它:
let controller = MyViewController()
controller.isModalInPresentation = true
self.present(controller, animated: true, completion: nil)
如果您使用故事板来布局您的 UI 我发现在使用导航控制器时禁用此交互式关闭的最佳方法是将属性检查器中导航控制器的显示从自动更改为全屏。导航堆栈中的所有视图控制器将全屏显示,用户将无法将其关闭。
Attribute Inspector showing presentation option for the navigation controller
Apple 分享了一个示例代码 at this link
它使用了 isModalInPresentation
个用户的建议。
您现在可以实现交互手势识别器的委托,并在尝试同时与滑块交互时禁用交互。这样,您可以保持交互式关闭,而滑块按预期工作。
您可以像这样禁用向下滑动:
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
})
如果您有一些业务逻辑,比如在关闭之前应该填写所有字段,您应该:
在 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
}
}
所有解决方案都很好,但就我而言,我需要一个停止移动的选项。
所以这是一个代码。
如果你想阻止移动:
self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = false
如果你想解锁移动:
self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = true
iOS 13 引入了 modalPresentationStyle
.pageSheet
(及其兄弟 .formSheet
)的新设计,用于模态呈现视图控制器…
…我们可以通过向下滑动呈现的视图控制器来关闭这些工作表(交互式关闭)。尽管新的 "pull-to-dismiss" 功能非常有用,但它可能并不总是令人满意的。
问题:我们怎样才能关闭交互式关闭? - 请记住,我们保持相同的演示风格。
选项 1:
viewController.isModalInPresentation = true
(禁用交互.pageSheet
解雇行为。)
- 由于 iOS 13,
UIViewController
包含一个名为isModalInPresentation
的新 属性,必须将其设置为true
以防止交互解雇。 - 它基本上忽略了视图控制器范围之外的事件。如果您不仅使用自动样式,还使用
.popover
等演示样式,请记住这一点。 - 这个属性默认是
false
。
From the official docs: If
true
, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.
选项 2:
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false
}
- 由于 iOS 13,
UIAdaptivePresentationControllerDelegate
包含一个名为presentationControllerShouldDismiss
的新方法。 - 仅当呈现的视图控制器未以编程方式关闭且其
isModalInPresentation
属性 设置为false
时才会调用此方法。
Tip: Don't forget to assign presentationController's delegate.
如果您想要与以前的 iOS 版本 (< iOS13) 相同的行为,例如全屏模型演示,只需设置目标视图的演示样式控制器到
UIModalPresentationStyle.fullScreen
let someViewController = \*VIEW CONTROLLER*\ someViewController.modalPresentationStyle = .fullScreen
如果您正在使用故事板,只需 select segua 和 select
Full Screen
形成Presentation
下拉列表。如果您只想禁用交互式解雇并保持新的演示文稿样式,请将
UIViewController
属性isModalInPresentation
设置为true
。if #available(iOS 13.0, *) { someViewController.isModalInPresentation = true // available in IOS13 }
属性 isModalInPresentation
可能会有帮助。
来自文档:
When you set it to
true
, UIKit ignores events outside the view controller's bounds and prevents the interactive dismissal of the view controller while it is onscreen.
你可以这样使用它:
let controller = MyViewController()
controller.isModalInPresentation = true
self.present(controller, animated: true, completion: nil)
如果您使用故事板来布局您的 UI 我发现在使用导航控制器时禁用此交互式关闭的最佳方法是将属性检查器中导航控制器的显示从自动更改为全屏。导航堆栈中的所有视图控制器将全屏显示,用户将无法将其关闭。
Attribute Inspector showing presentation option for the navigation controller
Apple 分享了一个示例代码 at this link
它使用了 isModalInPresentation
个用户的建议。
您现在可以实现交互手势识别器的委托,并在尝试同时与滑块交互时禁用交互。这样,您可以保持交互式关闭,而滑块按预期工作。
您可以像这样禁用向下滑动:
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
})
如果您有一些业务逻辑,比如在关闭之前应该填写所有字段,您应该:
在 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
}
}
所有解决方案都很好,但就我而言,我需要一个停止移动的选项。 所以这是一个代码。
如果你想阻止移动:
self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = false
如果你想解锁移动:
self.yourViewController?.presentedView?.gestureRecognizers?[0].isEnabled = true