ios 具有 UITapGestureRecognizer 的视图内的 UIButton
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3344341/
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
UIButton inside a view that has a UITapGestureRecognizer
提问by V1ru8
I have view with a UITapGestureRecognizer
. So when I tap on the view another view appears above this view. This new view has three buttons. When I now press on one of these buttons I don't get the buttons action, I only get the tap gesture action. So I'm not able to use these buttons anymore. What can I do to get the events through to these buttons? The weird thing is that the buttons still get highlighted.
我有一个UITapGestureRecognizer
. 因此,当我点击视图时,该视图上方会出现另一个视图。这个新视图有三个按钮。当我现在按下这些按钮之一时,我没有得到按钮动作,我只得到点击手势动作。所以我不能再使用这些按钮了。我该怎么做才能将事件传递到这些按钮?奇怪的是按钮仍然突出显示。
I can't just remove the UITapGestureRecognizer after I received it's tap. Because with it the new view can also be removed. Means I want a behavior like the fullscreen vide controls.
我不能在收到点击后删除 UITapGestureRecognizer。因为有了它,新视图也可以被删除。意味着我想要像全屏视频控件这样的行为。
回答by Lily Ballard
You can set your controller or view (whichever creates the gesture recognizer) as the delegate of the UITapGestureRecognizer
. Then in the delegate you can implement -gestureRecognizer:shouldReceiveTouch:
. In your implementation you can test if the touch belongs to your new subview, and if it does, instruct the gesture recognizer to ignore it. Something like the following:
您可以将控制器或视图(以创建手势识别器为准)设置为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
}
回答by cdasher
As a follow up to Casey's follow up to Kevin Ballard's answer:
作为凯西对凯文巴拉德回答的跟进:
- (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
}
This basically makes all user input types of controls like buttons, sliders, etc. work
这基本上使所有用户输入类型的控件(如按钮、滑块等)都能正常工作
回答by ejazz
Found this answer here: link
在这里找到这个答案:链接
You can also use
你也可以使用
tapRecognizer.cancelsTouchesInView = NO;
Which prevents the tap recognizer to be the only one to catch all the taps
这可以防止点击识别器成为唯一一个捕捉所有点击的人
UPDATE - Michaelmentioned the link to the documentation describing this property: cancelsTouchesInView
更新 - Michael提到了描述此属性的文档链接:cancelsTouchesInView
回答by Casey
As a follow up to Kevin Ballard's answer, I had this same problem and ended up using this code:
作为凯文巴拉德回答的后续,我遇到了同样的问题并最终使用了以下代码:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]){
return NO;
}
return YES;
}
It has the same effect but this will work on any UIButton at any view depth (my UIButton was several views deep and the UIGestureRecognizer's delegate didn't have a reference to it.)
它具有相同的效果,但它可以在任何视图深度的任何 UIButton 上工作(我的 UIButton 有多个视图深度,而 UIGestureRecognizer 的委托没有对它的引用。)
回答by Jagie
In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button's parent view, and the user taps the button, then the button's action method receives the touch event instead of the gesture recognizer. This applies only to gesture recognition that overlaps the default action for a control, which includes:.....
在 iOS 6.0 及更高版本中,默认控制操作可防止手势识别器行为重叠。例如,按钮的默认操作是单击。如果您将单击手势识别器附加到按钮的父视图,并且用户点击按钮,则按钮的操作方法将接收触摸事件而不是手势识别器。这仅适用于与控件的默认操作重叠的手势识别,其中包括:.....
回答by Sam B
These answers were incomplete. I had to read multiple posts as to how to use this boolean operation.
这些答案是不完整的。我不得不阅读多篇关于如何使用这个布尔运算的帖子。
In your *.h file add this
在你的 *.h 文件中添加这个
@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>
In your *.m file add this
在你的 *.m 文件中添加这个
- (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 ...");
}
回答by MindMirror
Found another way to do it from here. It detects the touch whether inside each button or not.
从这里找到了另一种方法。它检测触摸是否在每个按钮内。
(1) pointInside:withEvent:(2) locationInView:
(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]);
}
回答by John Riselvato
Here's the Swift version of Lily Ballard's answerthat worked for me:
这是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
}
回答by Shruthi Pal
Swift 5
斯威夫特 5
Button on superview with tapgesture
带有轻触手势的超级视图按钮
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let _ = touch.view as? UIButton { return false }
return true
}
In my case implementing hitTestworked for me. I had collection view with button
在我的情况下,实现hitTest对我有用。我有带按钮的集合视图
This method traverses the view hierarchy by calling the point(inside:with:)
method of each subview to determine which subview should receive a touch event. If point(inside:with:)
returns true, then the subview's hierarchy is similarly traversed until the frontmost view containing the specified point is found.
该方法通过调用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)
}
回答by Clay Bridges
Optimizing cdasher's answer, you get
优化 cdasher 的答案,你得到
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
return ![touch.view isKindOfClass:[UIControl class]];
}