ios UITapGestureRecognizer 点击 self.view 但忽略子视图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15814697/
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
UITapGestureRecognizer tap on self.view but ignore subviews
提问by Matrosov Alexander
I need to implement a feature that will invoke some code when I double tap on the self.view (view of UIViewCotroller
). But the problem that I have other UI object on this view and I don't want to attach any recognizer object to all of them. I found this method below how to make gesture on my view and I know how it works. Right now I am in front of handicap which way to choose for create this recognizer ignoring subview. Any ideas? Thanks.
我需要实现一个功能,当我双击 self.view(视图UIViewCotroller
)时会调用一些代码。但是问题是我在这个视图上有其他 UI 对象,我不想将任何识别器对象附加到所有这些对象上。我在下面找到了如何在我的视图上做手势的方法,我知道它是如何工作的。现在我在障碍面前选择哪种方式来创建这个忽略子视图的识别器。有任何想法吗?谢谢。
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleTap];
回答by Ravi
You should adopt the UIGestureRecognizerDelegate
protocol inside the self
object and call the below method for checking the view. Inside this method, check your view against touch.view
and return the appropriate bool (Yes/No). Something like this:
您应该采用对象UIGestureRecognizerDelegate
内部的协议self
并调用以下方法来检查视图。在此方法中,检查您的视图touch.view
并返回适当的布尔值(是/否)。像这样的东西:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:yourSubView]) {
return NO;
}
return YES;
}
Edit: Please, also check @Ian's answer!
编辑:请同时检查@Ian 的回答!
Swift 5
斯威夫特 5
// MARK: UIGestureRecognizerDelegate methods, You need to set the delegate of the recognizer
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view?.isDescendant(of: tableView) == true {
return false
}
return true
}
回答by Ian
Another approach is to just compare if the view of the touch is the gestures view, because descendants won't pass the condition. A nice, simple one-liner:
另一种方法是只比较触摸视图是否是手势视图,因为后代不会通过条件。一个漂亮、简单的单线:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
回答by Antoine
And for the Swift variant:
对于 Swift 变体:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(yourSubView){
return false
}
return true
}
Good to know, isDescendantOfView
returns a Boolean
value indicating whether the receiver is a subview of a given view or identical to that view.
很高兴知道,isDescendantOfView
返回一个Boolean
值,指示接收者是给定视图的子视图还是与该视图相同。
回答by Imanou Petit
With Swift 5 and iOS 12, UIGestureRecognizerDelegate
has a method called gestureRecognizer(_:shouldReceive:)
. gestureRecognizer(_:shouldReceive:)
has the following declaration:
在 Swift 5 和 iOS 12 中,UIGestureRecognizerDelegate
有一个名为gestureRecognizer(_:shouldReceive:)
. gestureRecognizer(_:shouldReceive:)
有以下声明:
Ask the delegate if a gesture recognizer should receive an object representing a touch.
询问代理手势识别器是否应该接收代表触摸的对象。
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
The complete code below shows a possible implementation for gestureRecognizer(_:shouldReceive:)
. With this code, a tap on a subview of the ViewController
's view (including imageView
) won't trigger the printHello(_:)
method.
下面的完整代码显示了gestureRecognizer(_:shouldReceive:)
. 使用此代码,点击ViewController
的视图(包括imageView
)的子视图不会触发该printHello(_:)
方法。
import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(printHello))
tapGestureRecognizer.delegate = self
view.addGestureRecognizer(tapGestureRecognizer)
let imageView = UIImageView(image: UIImage(named: "icon")!)
imageView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
view.addSubview(imageView)
// ?? Enable user interaction for imageView so that it can participate to touch events.
// Otherwise, taps on imageView will be forwarded to its superview and managed by it.
imageView.isUserInteractionEnabled = true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
// Prevent subviews of a specific view to send touch events to the view's gesture recognizers.
if let touchedView = touch.view, let gestureView = gestureRecognizer.view, touchedView.isDescendant(of: gestureView), touchedView !== gestureView {
return false
}
return true
}
@objc func printHello(_ sender: UITapGestureRecognizer) {
print("Hello")
}
}
An alternative implementation of gestureRecognizer(_:shouldReceive:)
can be:
的替代实现gestureRecognizer(_:shouldReceive:)
可以是:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return gestureRecognizer.view === touch.view
}
Note however that this alternative code does not check if touch.view
is a subview of gestureRecognizer.view
.
但是请注意,此替代代码不会检查是否touch.view
是gestureRecognizer.view
.
回答by Arru
Complete swift solution (delegate must be implemented AND set for recognizer(s) ):
完整的 swift 解决方案(必须实现委托并为识别器设置):
class MyViewController: UIViewController UIGestureRecognizerDelegate {
override func viewDidLoad() {
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(onBaseTapOnly))
doubleTapRecognizer.numberOfTapsRequired = 2
doubleTapRecognizer.delegate = self
self.view.addGestureRecognizer(doubleTapRecognizer)
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(self.view){
return false
}
return true
}
func onBaseTapOnly(sender: UITapGestureRecognizer) {
if sender.state == .Ended {
//react to tap
}
}
}
回答by CoachThys
Variant using CGPoint you touch (SWIFT 4.0)
使用您触摸的 CGPoint 的变体 (SWIFT 4.0)
class MyViewController: UIViewController, UIGestureRecognizerDelegate?{
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
// Get the location in CGPoint
let location = touch.location(in: nil)
// Check if location is inside the view to avoid
if viewToAvoid.frame.contains(location) {
return false
}
return true
}
}
回答by Musa almatri
Clear Swift way
清除 Swift 方式
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == self.view
}
回答by Rico
Note that the gestureRecognizer APIhas changed to:
请注意,gestureRecognizer API已更改为:
gestureRecognizer(_:shouldReceive:)
手势识别器(_:应该接收:)
Take particular note of the underscore (skip) indicator for the first parameter's external label.
请特别注意第一个参数的外部标签的下划线(跳过)指示符。
Using many of the examples provided above, I was not receiving the event. Below is a an example that works for current versions of Swift (3+).
使用上面提供的许多示例,我没有收到该事件。下面是一个适用于当前版本的 Swift (3+) 的示例。
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
var shouldReceive = false
if let clickedView = touch.view {
if clickedView == self.view {
shouldReceive = true;
}
}
return shouldReceive
}
回答by MrDEV
回答by Jonathan Cabrera
Swift 4:
斯威夫特 4:
touch.view
is now an optional, so based on @Antoine's answer:
touch.view
现在是可选的,因此基于@Antoine 的回答:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let touchedView = touch.view, touchedView.isDescendant(of: deductibleBackgroundView) {
return false
}
return true
}