在iOS 13中,可以使用平移手势关闭使用表单和页面工作表样式的模式演示。在我的一个表单中,这是有问题的,因为用户会拖入该框,从而干扰手势。它将屏幕向下拉,而不是绘制垂直线。
如何在显示为表格的模式视图控制器中禁用垂直滑动以消除手势?
设置isModalInPresentation = true
仍然可以将工作表拉下,只是不会消失。
答案 0 :(得分:38)
通常,对于将来的互联网旅行者来说,不应禁用滑动以关闭功能。但是,如果您的手势或触摸处理受到此功能的影响,我确实从Apple工程师那里收到了一些有关如何完成此操作的建议。
如果可以阻止系统的平移手势识别器启动,则可以防止手势解雇。几种方法可以做到这一点:
如果您的画布绘制是使用手势识别器(例如您自己的UIGestureRecognizer
子类)完成的,请在工作表的关闭手势之前进入began
阶段。如果您像UIPanGestureRecognizer
一样快地认出,您将获胜,并且工作表的关闭手势将被颠覆。
如果您的画布绘制是使用手势识别器完成的,请使用-shouldBeRequiredToFailByGestureRecognizer:
(或相关的委托方法)设置动态失败要求,如果传入的手势识别器返回NO
是UIPanGestureRecognizer
。
如果您的画布绘制是通过手动触摸处理完成的(例如touchesBegan:
),请在触摸处理视图上覆盖-gestureRecognizerShouldBegin
,如果传入了手势识别器,则返回NO
是UIPanGestureRecognizer
。
在我的设置3中,事实证明效果很好。这样一来,用户可以向下滑动绘图画布之外的任何位置以关闭它(例如导航栏),同时允许用户在不移动图纸的情况下进行绘图,就像人们期望的那样。
我不建议尝试找到禁用该手势的手势,因为它似乎是动态的,并且例如在不同大小的类之间切换时可以重新启用自身,并且在将来的版本中可能会更改。
答案 1 :(得分:5)
在提供的ViewController中,在viewDidLoad中使用它:
if #available(iOS 13.0, *) {
self.isModalInPresentation = true
}
答案 2 :(得分:4)
无需重新发明轮子。就像在 destinationViewController 上采用 UIAdaptivePresentationControllerDelegate
协议然后实现相关方法一样简单:
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
return false
}
例如,假设您的 destinationViewController 已准备好进行如下 segue:
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
或任何其他方法,以便正确处理您的自定义行为。>
答案 3 :(得分:3)
可以在模式视图控制器的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仍处于测试阶段,因此可能会在即将发布的版本中添加更简单的方法。
答案 4 :(得分:3)
您可以更改演示样式,如果在全屏模式下将禁用下拉菜单以关闭
navigationCont.modalPresentationStyle = .fullScreen
答案 5 :(得分:1)
您可以使用UIAdaptivePresentationControllerDelegate方法presentationControllerDidAttemptToDismiss并在presentedView上禁用gestureRecognizer。 像这样:
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
presentationController.presentedView?.gestureRecognizers?.first?.isEnabled = false
}
答案 6 :(得分:1)
就我而言,我有一个模态屏幕,其视图可以接收触摸以捕获客户签名。
在导航控制器中禁用手势识别器解决了该问题,从而完全避免了模态交互式解雇。
以下方法在我们的模式视图控制器中实现,并通过自定义签名视图中的委托进行调用。
从touchesBegan
致电:
private func disableDismissalRecognizers() {
navigationController?.presentationController?.presentedView?.gestureRecognizers?.forEach {
$0.isEnabled = false
}
}
从touchesEnded
致电:
private func enableDismissalRecognizers() {
navigationController?.presentationController?.presentedView?.gestureRecognizers?.forEach {
$0.isEnabled = true
}
}
标记为重复的这个问题更好地描述了我遇到的问题:Disabling interactive dismissal of presented view controller on iOS 13 when dragging from the main view
答案 7 :(得分:0)
我,我用这个:
-(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;
}
}
}
答案 8 :(得分:0)
对于每个在Jordans解决方案#3运行中遇到问题的人。
您必须寻找呈现的ROOT视图控制器,具体取决于您的视图堆栈,这可能不是您当前的视图。
我必须寻找我的导航控制器PresentationViewController。
顺便说一句@乔丹:谢谢!
UIGestureRecognizer *gesture = [[self.navigationController.presentationController.presentedView gestureRecognizers] firstObject];
if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer * pan = (UIPanGestureRecognizer *)gesture;
pan.delegate = self;
}
答案 9 :(得分:0)
将尝试更详细地描述@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
这是我的情况下代码的工作方式。没有它,滑动手势通常会被忽略,只能偶尔使用。
答案 10 :(得分:0)
在IOS 13中
draw.rect(BACKGROUND, tile_color, (WIDTH*.43, HEIGHT*4.99, WIDTH, HEIGHT), 2)
for column in range (2, 6, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*1.43, HEIGHT*(column+1.5), WIDTH, HEIGHT), 2)
for column in range (1, 8, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*2.43, HEIGHT*(column+1), WIDTH, HEIGHT), 2)
for column in range (1, 7, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*3.43, HEIGHT*(column+1.5), WIDTH, HEIGHT), 2)
for column in range (1, 8, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*4.43, HEIGHT*(column+1), WIDTH, HEIGHT), 2)
for column in range (1, 7, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*5.43, HEIGHT*(column+1.5), WIDTH, HEIGHT), 2)
for column in range (1, 8, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*6.43, HEIGHT*(column+1), WIDTH, HEIGHT), 2)
for column in range (2, 6, 1):
draw.rect(BACKGROUND, tile_color, (WIDTH*7.43, HEIGHT*(column+1.5), WIDTH, HEIGHT), 2)
draw.rect(BACKGROUND, tile_color, (WIDTH*8.4, HEIGHT*4.99, WIDTH, HEIGHT), 2)
答案 11 :(得分:0)
如果用户尝试滚动到滚动视图的顶端时,UITableView
或UICollectionView
启动页面取消手势,则可以通过添加不可见的{ {1}}立即调用UIRefreshControl
。
答案 12 :(得分:0)
在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
答案 13 :(得分:0)
您首先可以在viewDidAppear()方法中获得对处理页面工作表取消的UIPanGestureRecognizer的引用。注意,该引用在viewWillAppear()或viewDidLoad()中为nil。然后您只需禁用它即可。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
presentationController?.presentedView?.gestureRecognizers?.first.isEnabled = false
}
例如,如果要进行更多自定义设置而不是完全禁用它,则在页面表单中使用navBar时,请将该UIPanGestureRecognizer的委托设置为您自己的视图控制器。这样,您可以通过实现
在内容视图中专门禁用手势识别器,同时使其在navBar区域中保持活动状态。func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {}
答案 14 :(得分:-1)
对于导航控制器,为避免呈现视图的滑动交互,我们可以使用:
if #available(iOS 13.0, *) {navController.isModalInPresentation = true}