UITapGestureRecognizer коснитесь self.view, но игнорирует subviews
Мне нужно реализовать функцию, которая будет вызывать некоторый код при двойном нажатии на self.view(вид UIViewCotroller
). Но проблема в том, что у меня есть другой объект пользовательского интерфейса в этом представлении, и я не хочу прикреплять к нему всех объектов распознавателя. Я нашел этот метод ниже, как сделать жест на мой взгляд, и я знаю, как он работает. Прямо сейчас я перед гандикапом, который выбирает для создания этого распознавателя, игнорируя subview. Есть идеи? Спасибо.
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleTap];
Ответы
Ответ 1
Вы должны принять протокол UIGestureRecognizerDelegate
внутри объекта self
и вызвать метод ниже для проверки представления. Внутри этого метода проверьте свое мнение против touch.view
и верните соответствующий bool (Да/Нет). Что-то вроде этого:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:yourSubView]) {
return NO;
}
return YES;
}
Изменить: Пожалуйста, также проверьте @Ian ответ!
Ответ 2
Другой подход состоит в том, чтобы просто сравнить, является ли представление касания представлением жестов, потому что потомки не пройдут условие. Хороший, простой однострочник:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
Ответ 3
И для варианта Swift:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(yourSubView){
return false
}
return true
}
Полезно знать, isDescendantOfView
возвращает значение Boolean
, указывающее, является ли приемник подчиненным объектом данного представления или идентичным этому представлению.
Ответ 4
Полное быстрое решение (делегат должен быть реализован и установлен для распознавателя (-ов)):
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
}
}
}
Ответ 5
В Swift 5 и iOS 12 в UIGestureRecognizerDelegate
есть метод с именем gestureRecognizer(_:shouldReceive:)
. gestureRecognizer(_:shouldReceive:)
имеет следующее объявление:
Спросите делегата, должен ли распознаватель жестов получать объект, представляющий прикосновение.
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
Полный код ниже показывает возможную реализацию для gestureRecognizer(_:shouldReceive:)
. С этим кодом нажатие на ViewController
представления 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 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")
}
}
Альтернативной реализацией gestureRecognizer(_:shouldReceive:)
может быть:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return gestureRecognizer.view === touch.view
}
Однако обратите внимание, что этот альтернативный код не проверяет, является ли touch.view
gestureRecognizer.view
.
Ответ 6
Вариант с использованием 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
}
}
Ответ 7
Очистить Свифт путь
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == self.view
}
Ответ 8
Обратите внимание, что gestureRecognizer API изменился на:
gestureRecognizer (_: shouldReceive:)
Обратите внимание на индикатор подчеркивания (skip) для первой метки внешнего параметра.
Используя многие из приведенных выше примеров, я не получал событие. Ниже приведен пример, который работает для текущих версий 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
}
Ответ 9
Плюс вышеупомянутые решения, не забывайте проверять User Interaction Enabled
в вашем подчиненном представлении.
![enter image description here]()
Ответ 10
Свифт 4:
touch.view
теперь является необязательным, поэтому основан на ответе @Antoine:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let touchedView = touch.view, touchedView.isDescendant(of: deductibleBackgroundView) {
return false
}
return true
}
Ответ 11
Я должен был предотвратить жест на детском взгляде. Единственное, что сработало, это разрешить и сохранить первое представление и предотвратить жест во всех следующих представлениях:
var gestureView: UIView? = nil
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if (gestureView == nil || gestureView == touch.view){
gestureView = touch.view
return true
}
return false
}