我正在试图弄清楚如何以正确的方式完成。我试图描绘这种情况:
我正在添加UITableView
作为UIView
的子视图。 UIView
响应了tap-和pinchGestureRecognizer
,但是当这样做时,tableview会停止对这两个手势做出反应(它仍会对滑动作出反应)。
我已经使用以下代码,但它显然不是一个很好的解决方案,我相信有更好的方法。这是放在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];
}
答案 0 :(得分:180)
我遇到了一个非常类似的问题并找到了我的解决方案in this SO question。总之,请将自己设置为UIGestureRecognizer
的委托,然后在允许识别器处理触摸之前检查目标视图。相关的代表方法是:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
答案 1 :(得分:105)
将触摸事件阻止到子视图是默认行为。您可以更改此行为:
UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];
答案 2 :(得分:5)
我正在显示一个有自己的tableview的下拉子视图。因此,touch.view
有时会返回UITableViewCell
等类。我不得不单步执行超类(es)以确保它是我认为的子类:
-(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;
}
答案 3 :(得分:4)
一种可能性是将您的手势识别器子类化(如果您还没有)并覆盖-touchesBegan:withEvent:
,以便确定每次触摸是否在排除的子视图中开始,如果是,则调用-ignoreTouch:forEvent:
进行触摸那样。
显然,您还需要添加一个属性来跟踪被排除的子视图,或者更好的是,排除子视图数组。
答案 4 :(得分:4)
建立在@Pin Shih Wang answer。我们忽略除了包含轻敲手势识别器的视图上的所有水龙头。所有点击都会像我们设置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)
}
}
答案 5 :(得分:2)
可以不继承任何类。
你可以在手势的回调选择器
中查看gestureRecognizers如果view.gestureRecognizers不包含您的gestureRecognizer,请忽略它
例如
- (void)viewDidLoad
{
UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
singleTapGesture.numberOfTapsRequired = 1;
}
检查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
}
}
答案 6 :(得分:1)
我创建了一个UIGestureRecognizer子类,用于阻止附加到特定视图的超视图的所有手势识别器。
这是我的WEPopover项目的一部分。你可以找到它here。
答案 7 :(得分:0)
你可以关闭它......在我的代码中我做了类似这样的事情,因为我需要在键盘没有显示时关闭它,你可以将它应用到你的情况:
调用这是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];
然后创建两个方法:
-(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
}
这样做会禁用水龙头。我不得不将tap转换为实例变量并在dealloc中释放它。
答案 8 :(得分:0)
我也在做一个弹出窗口,这就是我做的方式
func didTap(sender: UITapGestureRecognizer) {
let tapLocation = sender.locationInView(tableView)
if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
sender.cancelsTouchesInView = false
}
else {
delegate?.menuDimissed()
}
}
答案 9 :(得分:0)
为parentView的所有识别器实现委托,并将gestureRecognizer方法放在委托中,该委托负责同时触发识别器:
func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool {
if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) {
return true
} else {
return false
}
}
如果你想让孩子被触发而不是父识别器,你可以使用失败方法:
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate