ScrollView手势识别器占用了所有触摸事件

47

我有一个UIScrollView,我为它添加了一个单击手势识别器,用于显示/隐藏一些UI叠加层,代码如下:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[scrollView addGestureRecognizer:singleTap];

和:

- (void)handleTap:(UITapGestureRecognizer *)sender {
    // report click to UI changer
}

我在UIScrollView底部添加了一个易于使用的表格视图。一切正常(横向和纵向滚动),但问题是轻击事件只被手势识别器(上方)所识别,而不是易于使用的表格视图。

如果我移除注册手势监听器的那行代码,一切都正常,表格视图也会注意到自己上的轻击。

就好像手势识别器函数“吃掉”了表格视图上的轻击事件,并且不向下传递它们。

感激任何帮助。

9个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
82

这应该可以解决您的问题。
在UIScrollView上检测触摸事件,以及在UIScrollView内放置的UIView组件上检测触摸事件
关键在于告诉手势识别器不要吞噬触摸事件。为此,您需要将singleTap的cancelsTouchesInView属性设置为NO,默认情况下为YES

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
singleTap.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:singleTap]; 

4
我有类似的问题(我的问题),但解决方案对我无效。有时事件会被触发,有时不会。 - new2ios
singleTap.cancelsTouchesInView = NO; 谢谢,这个解决方案帮助我在表视图中防止中断UITouch事件。 - Abhishek Thapliyal
1
我也遇到了类似的问题,不过我的问题是要么只高亮行(而不滚动),要么在没有先高亮行的情况下滚动(只有长按才有效)。我通过添加上述“cancelsTouchesInView = false”解决了这个问题,并确保tableView的“Can Cancel on Scroll”已选中且“Delay Touch Down”未选中(两者都可以在Interface Builder中轻松找到)。 - Merricat

15

Swift 3.0

 let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
 singleTap.cancelsTouchesInView = false
 singleTap.numberOfTapsRequired = 1
 scrollView.addGestureRecognizer(singleTap)

而选择器方法应该是这样的。

@objc func handleTap(_ recognizer: UITapGestureRecognizer) {
  // Perform operation
}

我不明白为什么这个解决方案对我不起作用。如果我使用UIView做所有的事情,那么一切都很好,但是如果我将UIView改为UIScrollView,它就停止工作了。 - Markus

10

我认为原因是UIImageView的 User Interaction Enabled 属性被设置为 false。您需要将其设置为true以启用其中的点按功能。


6
您可以设置哪些对象包括/排除触摸。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch {            
   if (touch.view == [self view]) {
       return YES;
   }
   return NO;
}

6

这对我在Swift 3 / Xcode 8中有效

self.scrollView.touchesShouldCancel(in: ** the view you want the touches in **)
self.scrollView.canCancelContentTouches = false

祝你好运!


3

感谢@zambrey

Swift 2.2+ 版本:

scrollView.delegate = self

let allowMultipleTouches = UITapGestureRecognizer(target: self, action: #selector(genderPressed))
allowMultipleTouches.numberOfTapsRequired = 1
allowMultipleTouches.cancelsTouchesInView = false

scrollView.addGestureRecognizer(allowMultipleTouches)

如果您的滚动视图在Storyboard中,不要忘记将Outlet固定在视图控制器中。在此示例中, scrollView UIScrollView 的Outlet。


2
对我来说很有效。另一方面,对于滑动操作,我必须禁用滚动才能正常运作。
swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeToNewImage(_:)))
swipeLeftGesture.direction = .left
scrollView.addGestureRecognizer(swipeLeftGesture)

swipeRightGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeToNewImage(_:)))
scrollView.addGestureRecognizer(swipeRightGesture)

scrollView.isScrollEnabled = false

当我这样做时,我的scrollView甚至在编程方式下也无法滚动(它会压缩元素以适应其容器)。 - agirault

1

您可以在UIscrollView中捕获任何类型的手势。确保您还处理一些默认属性,例如将cancelsTouchesInView属性设置为false,默认情况下为true。 还为子视图提供一些标记编号以在选择器中区分。 并且将它们的用户交互也设置为true。

let tap = UITapGestureRecognizer(target: self, action:

selector(didTapByUser(_:)))


0

我的代码。

我检查了所有提出的解决方案,但都无法为我工作。我不明白为什么。我不明白原因。

class MyClass: UITableViewController {

override func viewDidLoad() {
    super.viewDidLoad()

let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))

scrollView.contentSize = CGSize(width: UIScreen.main.bounds.size.width, height: 800)

scrollView.isUserInteractionEnabled = true
scrollView.delegate = self

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(manageGesture))

tap.cancelsTouchesInView = false

tap.numberOfTapsRequired = 1

scrollView.addGestureRecognizer(tap)

scrollView.canCancelContentTouches = false

self.view.addSubview(scrollView)

}

@objc func manageGesture(){
    // Some action
}


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,