在iOS 13中,可以使用平移手势关闭使用表单和页面工作表样式的模式演示。在我的一张表单中,这是有问题的,因为用户会拖入该框,从而干扰手势。它将屏幕下拉而不是画一条垂直线。
如何在以图纸形式显示的模态视图控制器中禁用垂直滑动以消除手势?
设置isModalInPresentation = true
仍然允许将工作表拉下,但不会关闭。
Answers:
通常,您不应该尝试禁用滑动以关闭功能,因为用户希望所有表单/页面在所有应用程序中的行为都相同。相反,您可能要考虑使用全屏演示样式。如果您确实想要使用无法通过滑动消除的纸张,请设置isModalInPresentation = true
,但请注意,这仍允许纸张垂直向下拉,并且在释放触摸时会弹起。请查看UIAdaptivePresentationControllerDelegate文档,以在用户尝试通过滑动将其关闭时做出反应。
如果您的应用程序的手势或触摸处理受到滑动以关闭功能的影响,我确实从Apple工程师那里收到了一些有关如何解决该问题的建议。
如果可以阻止系统的平移手势识别器启动,则可以防止手势解雇。一些方法可以做到这一点:
如果您的画布绘制是使用手势识别器(例如您自己的UIGestureRecognizer
子类)完成的,请began
在图纸的关闭手势之前输入阶段。如果您尽快识别UIPanGestureRecognizer
,您将获胜,并且工作表的关闭手势将被颠覆。
如果您的画布绘制是使用手势识别器完成的,请使用-shouldBeRequiredToFailByGestureRecognizer:
(或相关的委托方法)设置动态失败要求,NO
如果传入的手势识别器是,则在此处返回UIPanGestureRecognizer
。
如果您的画布绘制是通过手动触摸处理完成的(例如touchesBegan:
),请-gestureRecognizerShouldBegin
在触摸处理视图上进行覆盖,NO
如果传入的手势识别器为,则返回UIPanGestureRecognizer
。
在我的设置3中,事实证明效果很好。这样一来,用户可以向下滑动绘图画布之外的任何位置以关闭它(例如导航栏),同时允许用户在不移动图纸的情况下进行绘图,就像人们期望的那样。
我不建议尝试找到禁用该手势的手势,因为它似乎是动态的,并且例如在不同大小的类之间切换时可以重新启用自身,并且在将来的版本中可能会更改。
gestureRecognizer(_:,shouldRecognizeSimultaneouslyWith:)
来允许一些识别器一起工作,而另一些则不能。
UICollectionView
。如果我错了,请原谅我,但是我们不是必须成为解雇识别器的代表才能使用这些方法中的任何一种吗?
可以在模态视图控制器的 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仍处于测试阶段,因此可能会在即将发布的版本中添加更简单的方法。
尽管此解决方案目前似乎可以使用,但我不建议这样做,因为它在某些情况下可能无法使用,或者在将来的iOS版本中可能会更改,并可能影响您的应用。
viewWillAppear
放在所显示的视图控制器上-对segue很有用。🤗
UISwipeDismissalGestureRecognizer
。这可能是问题。
UITableView
也创造_UISwipeDismissalGestureRecognizer
。此外,如果您使用根视图控制器创建导航控制器,将堆栈以页面/表单的形式呈现出来,然后将另一个视图控制器推入其顶部,则向下滑动到撤消手势将通过手势识别器在UIView
层次结构的较高位置创建。如果没有苹果的禁止的明确支持刷卡下降到解雇触摸事件的处理,唯一可靠的解决方案(如Xcode中11的Beta 3的)是使用UIModalPresentationStyle
的UIModalPresentationFullScreen
。
for gesture in guestures where gesture.name == "_UISheetInteractionBackgroundDismissRecognizer" { gesture.isEnabled = false }
在提供的ViewController中,在viewDidLoad中使用它:
if #available(iOS 13.0, *) {
self.isModalInPresentation = true
}
isModalInPresentation = true
仍然允许将图纸拉下来,只是不放开,这可能正是您所需要的,或者取决于您的用例,这可能是有问题的,就像我的绘图画布一样。
self.modalPresentationStyle = .fullScreen
viewController.isModalInPresentation = true
为我工作
就我而言,我有一个模态屏幕,其视图可以接收触摸以捕获客户签名。
在导航控制器中禁用手势识别器可以解决该问题,从而完全避免触发模态交互式解雇。
以下方法在我们的模式视图控制器中实现,并通过自定义签名视图中的委托进行调用。
致电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上禁用交互式关闭呈现的视图控制器
您可以使用UIAdaptivePresentationControllerDelegate方法presentationControllerDidAttemptToDismiss并在presentedView上禁用gestureRecognizer。像这样:
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
presentationController.presentedView?.gestureRecognizers?.first?.isEnabled = false
}
对于每个人遇到乔丹解决方案3运行时遇到的问题。
您必须寻找呈现的ROOT ViewController,具体取决于您的视图堆栈,这可能不是您当前的视图。
我必须寻找我的导航控制器PresentationViewController。
BTW @乔丹:谢谢!
UIGestureRecognizer *gesture = [[self.navigationController.presentationController.presentedView gestureRecognizers] firstObject];
if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer * pan = (UIPanGestureRecognizer *)gesture;
pan.delegate = self;
}
我,我用这个:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
for(UIGestureRecognizer *gr in self.presentationController.presentedView.gestureRecognizers) {
if (@available(iOS 11.0, *)) {
if([gr.name isEqualToString:@"_UISheetInteractionBackgroundDismissRecognizer"]) {
gr.enabled = false;
}
}
}
将尝试更详细地描述@Jordan H建议的方法2:
1)为了能够捕获并做出关于模式表的平移手势的决定,请将其添加到视图控制器的中viewDidLoad
:
navigationController?.presentationController?.presentedView?.gestureRecognizers?.forEach {
$0.delegate = self
}
2)能够使用以下命令捕捉平移手势和您自己的手势 gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
3)实际的决定可以进去 gestureRecognizer(_:shouldBeRequiredToFailBy:)
示例代码,如果同时存在滑动手势,则其优先于工作表的平移手势。在没有滑动手势识别器的区域中,它不会影响原始的平移手势,因此原始的“滑动以关闭”仍可以按设计工作。
extension PeopleViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer === UIPanGestureRecognizer.self && otherGestureRecognizer === UISwipeGestureRecognizer.self {
return true
}
return false
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
就我而言,我只有几个滑动手势识别器,所以比较类型对我来说就足够了,但是如果有更多的手势识别器,则比较手势识别器本身(以编程方式添加的手势识别器或作为界面生成器的出口)比较有意义,如下所述这份文件:https : //developer.apple.com/documentation/uikit/touches_presses_and_gestures/coordinating_multiple_gesture_recognizers/preferring_one_gesture_over_another
这是我的情况下代码的工作方式。没有它,滑动手势通常会被忽略,并且只能偶尔使用。
viewDidAppear
(因为我presentationController
为nil时,我只是在道德上提出了vc)。并且,我迭代其视图的监督,以发现该视图具有PanGesture
,并将其委托设置为self
。然后我的vc无法向下滑动以关闭,是否还有其他方法可以解决我的问题?请帮忙
当用户尝试滚动到滚动视图的顶端时,如果aUITableView
或UICollectionView
启动页面取消手势,可以通过添加一个不可见的UIRefreshControl
调用来禁用此手势。endRefreshing
立即。
在prepare(for:sender :)中:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == viewControllerSegueID {
let controller = segue.destination as! YourViewController
controller.modalPresentationStyle = .fullScreen
}
}
或者,在初始化控制器后:
let controller = YourViewController()
controller.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 {}
对于导航控制器,为避免呈现视图的滑动交互,我们可以使用:
if #available(iOS 13.0, *) {navController.isModalInPresentation = true}