ios UIGestureRecognizer 阻止子视图处理触摸事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5222998/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIGestureRecognizer blocks subview for handling touch events
提问by andershqst
I'm trying to figure out how this is done the right way. I've tried to depict the situation:
我试图弄清楚这是如何以正确的方式完成的。我试图描述这种情况:
I'm adding a UITableView
as a subview of a UIView
. The UIView
responds to a tap- and pinchGestureRecognizer
, but when doing so, the tableview stops reacting to those two gestures (it still reacts to swipes).
我正在添加 aUITableView
作为 a 的子视图UIView
。在UIView
一个分接开关和响应pinchGestureRecognizer
,但这样做的情况下,实现代码如下停止反应,这两个手势(它仍然反应刷卡)。
I've made it work with the following code, but it's obviously not a nice solution and I'm sure there is a better way. This is put in the UIView
(the superview):
我已经用下面的代码让它工作了,但这显然不是一个很好的解决方案,我相信有更好的方法。这是放在UIView
(超级视图)中:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if([super hitTest:point withEvent:event] == self) {
for (id gesture in self.gestureRecognizers) {
[gesture setEnabled:YES];
}
return self;
}
for (id gesture in self.gestureRecognizers) {
[gesture setEnabled:NO];
}
return [self.subviews lastObject];
}
回答by Justin
I had a very similar problem and found my solution in this SO question. In summary, set yourself as the delegate for your UIGestureRecognizer
and then check the targeted view before allowing your recognizer to process the touch. The relevant delegate method is:
我有一个非常相似的问题,并在这个 SO question 中找到了我的解决方案。总之,将自己设置为您的代理UIGestureRecognizer
,然后在允许您的识别器处理触摸之前检查目标视图。相关的委托方法是:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
回答by Clive Paterson
The blocking of touch events to subviews is the default behaviour. You can change this behaviour:
阻止子视图的触摸事件是默认行为。您可以更改此行为:
UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];
回答by joslinm
I was displaying a dropdown subview that had its own tableview. As a result, the touch.view
would sometimes return classes like UITableViewCell
. I had to step through the superclass(es) to ensure it was the subclass I thought it was:
我正在显示一个下拉子视图,它有自己的表视图。因此,touch.view
有时会返回像UITableViewCell
. 我必须遍历超类以确保它是我认为的子类:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
UIView *view = touch.view;
while (view.class != UIView.class) {
// Check if superclass is of type dropdown
if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own
NSLog(@"Is of type dropdown; returning NO");
return NO;
} else {
view = view.superview;
}
}
return YES;
}
回答by Caleb
One possibility is to subclass your gesture recognizer (if you haven't already) and override -touchesBegan:withEvent:
such that it determines whether each touch began in an excluded subview and calls -ignoreTouch:forEvent:
for that touch if it did.
一种可能性是将您的手势识别器(如果您还没有)子类化并覆盖-touchesBegan:withEvent:
,以便它确定每个触摸是否在排除的子视图中开始,-ignoreTouch:forEvent:
如果是,则调用该触摸。
Obviously, you'll also need to add a property to keep track of the excluded subview, or perhaps better, an array of excluded subviews.
显然,您还需要添加一个属性来跟踪排除的子视图,或者更好的是,一组排除的子视图。
回答by Nick Ager
Building on @Pin Shih Wang answer. We ignore all taps other than those on the view containing the tap gesture recognizer. All taps are forwarded to the view hierarchy as normal as we've set tapGestureRecognizer.cancelsTouchesInView = false
. Here is the code in Swift3/4:
基于@Pin Shih Wang 的回答。我们忽略除包含点击手势识别器的视图之外的所有点击。所有点击都像我们设置的一样正常转发到视图层次结构tapGestureRecognizer.cancelsTouchesInView = false
。这是 Swift3/4 中的代码:
func ensureBackgroundTapDismissesKeyboard() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tapGestureRecognizer.cancelsTouchesInView = false
self.view.addGestureRecognizer(tapGestureRecognizer)
}
@objc func handleTap(recognizer: UIGestureRecognizer) {
let location = recognizer.location(in: self.view)
let hitTestView = self.view.hitTest(location, with: UIEvent())
if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) {
// I dismiss the keyboard on a tap on the scroll view
// REPLACE with own logic
self.view.endEditing(true)
}
}
回答by Pin Shih Wang
It is possible to do without inherit any class.
可以不继承任何类。
you can check gestureRecognizers in gesture's callback selector
您可以在手势的回调选择器中检查gestureRecognizers
if view.gestureRecognizers not contains your gestureRecognizer,just ignore it
如果 view.gestureRecognizers 不包含您的gestureRecognizer,请忽略它
for example
例如
- (void)viewDidLoad
{
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
singleTapGesture.numberOfTapsRequired = 1;
}
check view.gestureRecognizers here
在此处检查 view.gestureRecognizers
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
UIEvent *event = [[UIEvent alloc] init];
CGPoint location = [gestureRecognizer locationInView:self.view];
//check actually view you hit via hitTest
UIView *view = [self.view hitTest:location withEvent:event];
if ([view.gestureRecognizers containsObject:gestureRecognizer]) {
//your UIView
//do something
}
else {
//your UITableView or some thing else...
//ignore
}
}
回答by Werner Altewischer
回答by user7270881
implement a delegate for all the recognizers of the parentView and put the gestureRecognizer method in the delegate that is responsible for simultaneous triggering of recognizers:
为 parentView 的所有识别器实现一个委托,并将gestureRecognizer 方法放在负责同时触发识别器的委托中:
func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool {
if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) {
return true
} else {
return false
}
}
}
U can use the fail methods if u want to make the children be triggered but not the parent recognizers:
如果你想让孩子被触发而不是父识别器,你可以使用失败方法:
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate
回答by Maria
I was also doing a popover and this is how I did it
我也在做一个popover,这就是我做的
func didTap(sender: UITapGestureRecognizer) {
let tapLocation = sender.locationInView(tableView)
if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
sender.cancelsTouchesInView = false
}
else {
delegate?.menuDimissed()
}
}
回答by j2emanue
You can turn it off and on.... in my code i did something like this as i needed to turn it off when the keyboard was not showing, you can apply it to your situation:
您可以关闭和打开它....在我的代码中,我做了这样的事情,因为我需要在键盘未显示时将其关闭,您可以将其应用于您的情况:
call this is viewdidload etc:
称之为 viewdidload 等:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
then create the two methods:
然后创建两个方法:
-(void) notifyShowKeyboard:(NSNotification *)inNotification
{
tap.enabled=true; // turn the gesture on
}
-(void) notifyHideKeyboard:(NSNotification *)inNotification
{
tap.enabled=false; //turn the gesture off so it wont consume the touch event
}
What this does is disables the tap. I had to turn tap into a instance variable and release it in dealloc though.
这样做是禁用水龙头。我不得不将 tap 变成一个实例变量并在 dealloc 中释放它。