如何禁用以表单形式呈现的模态视图控制器中的垂直滑动关闭手势?
设置
isModalInPresentation = true
仍然允许下拉该sheet,只是不会关闭。isModalInPresentation = true
仍然允许下拉该sheet,只是不会关闭。isModalInPresentation=true
,但请注意,这仍然允许按垂直方向拉下表格,在释放触摸时它会弹回来。查看UIAdaptivePresentationControllerDelegate文档,以便在用户尝试通过滑动将其解除等操作时作出反应。UIGestureRecognizer
子类,则必须在表格的解除手势之前进入began
阶段。如果您能像UIPanGestureRecognizer
一样快速识别,则会获胜,并且表格的解除手势将被挫败。如果您的画布绘图是使用手势识别器完成的,请使用-shouldBeRequiredToFailByGestureRecognizer:
(或相关的委托方法)设置动态失败要求,其中如果传入的手势识别器是一个UIPanGestureRecognizer
,则返回NO
。
如果您的画布绘制是通过手动触摸处理完成的(例如touchesBegan:
),请在您的触摸处理视图上覆盖-gestureRecognizerShouldBegin
并在传入的手势识别器是UIPanGestureRecognizer
时返回NO
。
对于我的设置,方案#3非常有效。这使用户可以在绘图画布之外的任何地方向下滑动以关闭(例如导航栏),同时允许用户绘制而不移动该页,就像预期一样。
我不能推荐尝试找到禁用手势的方法,因为它似乎相当动态,并且在切换不同大小类别时可以重新启用自己,而这在未来的版本中可能会改变。
gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
来允许一些识别器一起工作,而其他识别器则不行。 - DougUICollectionView
。如果我错了,请原谅,但是难道我们不必成为解除识别器的代表才能利用这些方法吗? - simonthumper这个手势可以在模态视图控制器的presentedView
属性中找到。调试时,该属性的gestureRecognizers
数组只有一个项目,并将其打印出来的结果类似于以下内容:
UIPanGestureRecognizer: 0x7fd3b8401aa0 (_UISheetInteractionBackgroundDismissRecognizer);
因此,要禁用此手势,您可以执行以下操作:
let vc = UIViewController()
self.present(vc, animated: true, completion: {
vc.presentationController?.presentedView?.gestureRecognizers?[0].isEnabled = false
})
要重新启用它,只需将 isEnabled
设置为 true
:vc.presentationController?.presentedView?.gestureRecognizers?[0].isEnabled = true
请注意,iOS 13仍处于测试版阶段,因此在未来的版本中可能会添加更简单的方法。UISwipeDismissalGestureRecognizer
。这可能是问题所在。 - M RezaUITableView
也会创建 _UISwipeDismissalGestureRecognizer
。此外,如果您创建了一个带有根视图控制器的导航控制器,并将堆栈以页面/表单表的形式模态呈现,并在其上推入另一个视图控制器,则通过从 UIView
层次结构中的更高位置创建的手势识别器向下滑动以解除的手势将解除整个堆栈。在没有苹果显式支持禁用向下滑动以解除触摸事件处理的情况下,唯一可靠的解决方案(截至 Xcode 11 beta 3)是使用 UIModalPresentationStyle
的 UIModalPresentationFullScreen
。 - Gary对于 guestures 中的每个手势,如果 gesture.name 等于 "_UISheetInteractionBackgroundDismissRecognizer",则将 gesture.isEnabled 设置为 false。
- spfursich在展示的 ViewController 的 viewDidLoad 中使用此方法:
if #available(iOS 13.0, *) {
self.isModalInPresentation = true
}
self.modalPresentationStyle = .fullScreen
。我会尽力使翻译更加通俗易懂,但不会改变原意或添加其他内容,也不会提供解释。 - Zoltan VinklerviewController.isModalInPresentation = true
对我有用。 - BharathRao就我而言,我有一个模态屏幕,其中的视图接收触摸以捕获客户签名。
禁用导航控制器中的手势识别器解决了问题,完全防止了模态交互式解除触发。
我们的模态视图控制器中实现了以下方法,并通过自定义签名视图通过委托调用。
从 touchesBegan
调用:
private func disableDismissalRecognizers() {
navigationController?.presentationController?.presentedView?.gestureRecognizers?.forEach {
$0.isEnabled = false
}
}
从 touchesEnded
调用:
private func enableDismissalRecognizers() {
navigationController?.presentationController?.presentedView?.gestureRecognizers?.forEach {
$0.isEnabled = true
}
}
这个被标记为重复的问题更好地描述了我遇到的问题:在iOS 13上,当从主视图拖动时禁用呈现的视图控制器的交互式取消
navigationController?.presentationController?.presentedView
总是为nil
。我尝试使用navigationController?.presentationController?.presentedViewController.view
,但是找不到_UISheetInteractionBackgroundDismissRecognizer
... - IdonavigationController
总是空的,因此我能够使用 presentationController?.presentedView?.gestureRecognizers?.forEach
访问它。 - Chuck Krutsingerself.presentationController?.presentedView?.gestureRecognizers?
而不是navigationController?.presentationController?.presentedView?.gestureRecognizers?
。请参见@M Reza的答案。 - J KasparianscrollViewWillBeginDragging
和scrollViewWillEndDragging
中调用(以及使用self.presentationController而不是包括navigationController),但是当我滚动tableview时,模态仍然会有时下拉。 - thesuffering没有必要重复造轮子。只需要在你的destinationViewController上采用UIAdaptivePresentationControllerDelegate
协议,然后实现相关方法即可:
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false
}
例如,假设您的目标视图控制器已经准备好像下面这样进行转场:override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourIdentifier",
let destinationVC = segue.destination as? DetailViewController
{
//do other stuff
destinationVC.presentationController?.delegate = destinationVC
}
}
然后在采用上述协议的destinationVC
上,你可以实现描述的方法func presentationControllerShouldDismiss(_ presentationController:) -> Bool
或其他任何方法,以便正确处理自定义行为。
prepare(for:sender:)
中设置委托,您可以在 viewDidLoad
中设置 presentationController?.delegate = self
。这样所有代码都在一个视图控制器中。 - Allanah Fowler如果全屏显示,您可以更改演示文稿的样式,此时下拉以解除禁用
navigationCont.modalPresentationStyle = .fullScreen
你可以在viewDidAppear()方法中首先获取对UIPanGestureRecognizer进行处理的引用,以进行页面表单的关闭。请注意,在viewWillAppear()或viewDidLoad()方法中,此引用为nil。然后,您只需禁用它。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
presentationController?.presentedView?.gestureRecognizers?.first.isEnabled = false
}
如果你想进行更多的自定义,而不是完全禁用它,例如在页面表中使用navBar时,将UIPanGestureRecognizer的代理设置为你自己的视图控制器。这样,你就可以在实现时专门在你的contentView中禁用手势识别器,同时保持它在你的navBar区域活动状态。
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {}
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
presentationController.presentedView?.gestureRecognizers?.first?.isEnabled = false
}
对于每个在运行Jordans解决方法#3时遇到问题的人。
您需要查找被呈现的根视图控制器,这取决于您的视图堆栈,这可能不是您当前的视图。
我不得不寻找我的导航控制器PresentationViewController。
顺便说一句@Jordam:谢谢!
UIGestureRecognizer *gesture = [[self.navigationController.presentationController.presentedView gestureRecognizers] firstObject];
if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer * pan = (UIPanGestureRecognizer *)gesture;
pan.delegate = self;
}
iOS 13中
if #available(iOS 13.0, *) {
obj.isModalInPresentation = true
} else {
// Fallback on earlier versions
}