我有一个带有UITapGestureRecognizer
的视图。因此,当我点击该视图时,另一个视图会出现在该视图上方。这个新视图有三个按钮。当我现在按下其中一个按钮时,我不能获得按钮的动作,我只能获得点击手势的动作。所以我无法再使用这些按钮。我该怎么做才能将事件传递给这些按钮呢?奇怪的是,这些按钮仍然会被突出显示。
我不能只是在接收到点击手势后删除UITapGestureRecognizer
。因为带有它,新视图也可以被移除。我的意思是,我想要像全屏视频控件那样的行为。
我有一个带有UITapGestureRecognizer
的视图。因此,当我点击该视图时,另一个视图会出现在该视图上方。这个新视图有三个按钮。当我现在按下其中一个按钮时,我不能获得按钮的动作,我只能获得点击手势的动作。所以我无法再使用这些按钮。我该怎么做才能将事件传递给这些按钮呢?奇怪的是,这些按钮仍然会被突出显示。
我不能只是在接收到点击手势后删除UITapGestureRecognizer
。因为带有它,新视图也可以被移除。我的意思是,我想要像全屏视频控件那样的行为。
您可以将控制器或视图(无论哪一个创建了手势识别器)设置为UITapGestureRecognizer
的代理。然后在代理中,您可以实现-gestureRecognizer:shouldReceiveTouch:
。在您的实现中,您可以测试触摸是否属于您的新子视图,如果是,则指示手势识别器忽略它。类似以下内容:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// test if our control subview is on-screen
if (self.controlSubview.superview != nil) {
if ([touch.view isDescendantOfView:self.controlSubview]) {
// we touched our control surface
return NO; // ignore the touch
}
}
return YES; // handle the touch
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIControl class]]) {
// we touched a button, slider, or other UIControl
return NO; // ignore the touch
}
return YES; // handle the touch
}
这基本上使所有用户输入类型的控件,如按钮、滑块等,都能够工作。
setCancelsTouchesInView = NO
使用,以避免与控件交互时触发轻拍手势。不过你可以写得更好:
return ![touch.view isKindOfClass:[UIControl class]];
- griga13在这里找到了答案:链接
你也可以使用
tapRecognizer.cancelsTouchesInView = NO;
这可以防止轻拍识别器成为唯一捕获所有轻拍的识别器。
更新 - Michael提到了文档中描述此属性的链接:cancelsTouchesInView
作为对Kevin Ballard答案的跟进,我遇到了相同的问题并最终使用了这段代码:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]){
return NO;
}
return YES;
}
这具有相同的效果,但是这将适用于任何深度的视图中的任何UIButton(我的UIButton位于多个视图深度中,而UIGestureRecognizer的委托没有引用它。)
这些答案不完整。我不得不阅读多篇帖子,才能了解如何使用此布尔操作。
在您的 *.h 文件中添加以下内容:
@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
NSLog(@"went here ...");
if ([touch.view isKindOfClass:[UIControl class]])
{
// we touched a button, slider, or other UIControl
return NO; // ignore the touch
}
return YES; // handle the touch
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//tap gestrure
UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)];
[tapGestRecog setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:tapGestRecog];
// This line is very important. if You don't add it then your boolean operation will never get called
tapGestRecog.delegate = self;
}
-(IBAction) screenTappedOnce
{
NSLog(@"screenTappedOnce ...");
}
我从这里找到了另一种方法。它检测每个按钮内部的触摸。
(1) pointInside:withEvent: 方法。 (2) locationInView: 方法。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
// Don't recognize taps in the buttons
return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] &&
![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] &&
![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]);
}
Swift 5
在父视图上使用按钮和轻拍手势
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let _ = touch.view as? UIButton { return false }
return true
}
point(inside:with:)
方法来遍历视图层次结构,以确定哪个子视图应该接收触摸事件。如果point(inside:with:)
返回true,则类似地遍历子视图的层次结构,直到找到包含指定点的最前面的视图。override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard isUserInteractionEnabled else { return nil }
guard !isHidden else { return nil }
guard alpha >= 0.01 else { return nil }
guard self.point(inside: point, with: event) else { return nil }
for eachImageCell in collectionView.visibleCells {
for eachImageButton in eachImageCell.subviews {
if let crossButton = eachImageButton as? UIButton {
if crossButton.point(inside: convert(point, to: crossButton), with: event) {
return crossButton
}
}
}
}
return super.hitTest(point, with: event)
}
这是我用过的Lily Ballard的答案的Swift版本:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if (scrollView.superview != nil) {
if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false }
}
return true
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
return ![touch.view isKindOfClass:[UIControl class]];
}
void
,因此在运行时不会留下任何信息用于检测。但是您可以沿着视图层次结构向上遍历,测试UIControl
,如果找到任何控件,则返回NO
。 - Lily Ballard