Je dois implémenter une fonctionnalité qui invoquera du code lorsque je double frappe sur le fichier self.view (vue de UIViewCotroller
). Mais le problème est que j'ai un autre objet d'interface utilisateur sur cette vue et que je ne souhaite pas attacher d'objet de reconnaissance à tous. J'ai trouvé cette méthode ci-dessous comment faire un geste sur ma vue et je sais comment cela fonctionne. En ce moment, je suis devant le handicap de quelle manière choisir pour créer cette reconnaissance en ignorant la sous-vue. Des idées? Merci.
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleTap];
Vous devez adopter le protocole UIGestureRecognizerDelegate
à l'intérieur de l'objet self
et appeler la méthode ci-dessous pour vérifier la vue. Dans cette méthode, vérifiez votre vue par rapport à touch.view
et renvoyez le booléen approprié (Oui/Non). Quelque chose comme ça:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:yourSubView]) {
return NO;
}
return YES;
}
Edit: S'il vous plaît, vérifiez également la réponse de @ Ian!
Une autre approche consiste simplement à comparer si la vue tactile est la vue gestuelle, car les descendants ne passeront pas la condition. Un beau, simple one-liner:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == gestureRecognizer.view
}
Et pour la variante Swift:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(yourSubView){
return false
}
return true
}
Bon à savoir, isDescendantOfView
renvoie une valeur Boolean
indiquant si le destinataire est une sous-vue d'une vue donnée ou identique à cette vue.
Solution Swift complète (le délégué doit être implémenté ET défini pour le ou les dispositifs de reconnaissance):
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
}
}
}
Avec iOS 11 et Swift 4.2, UIGestureRecognizerDelegate
dispose d'une méthode appelée gestureRecognizer(_:shouldReceive:)
. gestureRecognizer(_:shouldReceive:)
a la déclaration suivante:
Demandez au délégué si un dispositif de reconnaissance de geste doit recevoir un objet représentant une touche.
optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
Le code complet ci-dessous montre une implémentation possible pour gestureRecognizer(_:shouldReceive:)
. Avec ce code, un tap sur une sous-vue de la vue ViewController
(y compris imageView
) ne déclenchera pas la méthode 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")
}
}
Une autre implémentation de gestureRecognizer(_:shouldReceive:)
peut être:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return gestureRecognizer.view === touch.view
}
Notez cependant que ce code alternatif ne vérifie pas si touch.view
est une sous-vue de gestureRecognizer.view
.
Clair Swift Way
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view == self.view
}
Variante utilisant CGPoint que vous touchez (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
}
}
Notez que l'API gestureRecognizer a été modifiée en:
gestureRecognizer (_: shouldReceive :)
Prenez particulièrement note de l’indicateur de soulignement (saut) de l’étiquette externe du premier paramètre.
En utilisant plusieurs des exemples fournis ci-dessus, je ne recevais pas l'événement. Vous trouverez ci-dessous un exemple qui fonctionne pour les versions actuelles de 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
}
Je devais empêcher le geste sur la vue de l'enfant. La seule chose qui a fonctionné est d’autoriser et de conserver la première vue et d’empêcher les gestes dans toutes les vues suivantes:
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
}
Swift 4:
touch.view
est maintenant optionnel, donc basé sur la réponse de @ Antoine
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if let touchedView = touch.view, touchedView.isDescendant(of: deductibleBackgroundView) {
return false
}
return true
}