Comment ajouter un événement tactile à une UIView?

280

Comment ajouter un événement tactile à une UIView?
J'essaie:

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)] autorelease];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];
// ERROR MESSAGE: UIView may not respond to '-addTarget:action:forControlEvents:'

Je ne veux pas créer de sous-classe et écraser

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
Manni
la source
Pour plus de rapidité, vous pouvez l'obtenir à partir d'ici: stackoverflow.com/questions/28675209/…
Mr.Javed Multani

Réponses:

578

Dans iOS 3.2 et supérieur, vous pouvez utiliser des reconnaisseurs de gestes. Par exemple, voici comment gérer un événement tap:

//The setup code (in viewDidLoad in your view controller)
UITapGestureRecognizer *singleFingerTap = 
  [[UITapGestureRecognizer alloc] initWithTarget:self 
                                          action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];

//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
  CGPoint location = [recognizer locationInView:[recognizer.view superview]];

  //Do stuff here...
}

Il existe également un tas de gestes intégrés. Consultez les documents pour la gestion des événements iOS et UIGestureRecognizer. J'ai également un tas d'exemples de code sur github qui pourraient aider.

Nathan Eror
la source
Mais cela remplace l'action tactile par défaut de la vue. ¿Est-il possible d'appeler l'action tactile par défaut de la vue? Quelque chose comme [super touchesBegan]? ...
M Penades
2
Que fait la ligne CGPoint?
zakdances
2
@yourfriendzak the CGPointreprésente l'emplacement du robinet dans la vue d'ensemble de la vue tapée. Vous pouvez utiliser ce point pour déplacer la vue taraudée (ou une vue frère) vers l'emplacement taraudé. Ceci est plus utile dans le gestionnaire pour UIPanGestureRecognizerfaire glisser la vue sur l'écran.
Nathan Eror
5
grande réponse concise, merci. mais sheesh, ça ne serait pas bien si c'était un peu plus facile?! :)
natbro
Ce n'est pas trop mal, mais j'aimerais qu'il y ait une API basée sur des blocs comme github.com/neror/ftutils/blob/master/Headers/FTUtils/… . Xcode 4 prend également en charge l'ajout / la configuration de reconnaisseurs de gestes dans Interface Builder.
Nathan Eror
126

Reconnaisseurs de gestes

Il existe un certain nombre d'événements tactiles (ou gestes) couramment utilisés dont vous pouvez être averti lorsque vous ajoutez un identificateur de geste à votre vue. Les types de mouvements suivants sont pris en charge par défaut:

  • UITapGestureRecognizer Appuyez (en touchant brièvement une ou plusieurs fois l'écran)
  • UILongPressGestureRecognizer Toucher long (toucher l'écran pendant longtemps)
  • UIPanGestureRecognizer Pan (en déplaçant votre doigt sur l'écran)
  • UISwipeGestureRecognizer Glisser (déplacer rapidement le doigt)
  • UIPinchGestureRecognizer Pincer (en rapprochant ou en écartant deux doigts - généralement pour zoomer)
  • UIRotationGestureRecognizer Rotation (déplacement de deux doigts dans une direction circulaire)

En plus de cela, vous pouvez également créer votre propre outil de reconnaissance des gestes personnalisé.

Ajout d'un geste dans le générateur d'interface

Faites glisser un identificateur de mouvements de la bibliothèque d'objets vers votre vue.

entrez la description de l'image ici

Contrôlez le glisser depuis le geste dans le plan du document vers votre code View Controller afin de créer une sortie et une action.

entrez la description de l'image ici

Cela doit être défini par défaut, mais assurez-vous également que l'action utilisateur activée est définie sur true pour votre affichage.

entrez la description de l'image ici

Ajout d'un geste par programme

Pour ajouter un geste par programmation, vous (1) créez un identificateur de geste, (2) l'ajoutez à une vue et (3) créez une méthode qui est appelée lorsque le geste est reconnu.

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1. create a gesture recognizer (tap gesture)
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
        
        // 2. add the gesture recognizer to a view
        myView.addGestureRecognizer(tapGesture)
    }
    
    // 3. this method is called when a tap is recognized
    @objc func handleTap(sender: UITapGestureRecognizer) {
        print("tap")
    }
}

Remarques

  • Le senderparamètre est facultatif. Si vous n'avez pas besoin d'une référence au geste, vous pouvez le laisser de côté. Si vous le faites, supprimez le (sender:)nom après la méthode d'action.
  • La dénomination de la handleTapméthode était arbitraire. Nommez-le comme vous le souhaitez .action: #selector(someMethodName(sender:))

Plus d'exemples

Vous pouvez étudier les reconnaisseurs de mouvements que j'ai ajoutés à ces vues pour voir comment ils fonctionnent.

entrez la description de l'image ici

Voici le code de ce projet:

import UIKit
class ViewController: UIViewController {
    
    @IBOutlet weak var tapView: UIView!
    @IBOutlet weak var doubleTapView: UIView!
    @IBOutlet weak var longPressView: UIView!
    @IBOutlet weak var panView: UIView!
    @IBOutlet weak var swipeView: UIView!
    @IBOutlet weak var pinchView: UIView!
    @IBOutlet weak var rotateView: UIView!
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Tap
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapView.addGestureRecognizer(tapGesture)
        
        // Double Tap
        let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
        doubleTapGesture.numberOfTapsRequired = 2
        doubleTapView.addGestureRecognizer(doubleTapGesture)
        
        // Long Press
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gesture:)))
        longPressView.addGestureRecognizer(longPressGesture)
        
        // Pan
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
        panView.addGestureRecognizer(panGesture)
        
        // Swipe (right and left)
        let swipeRightGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        let swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        swipeRightGesture.direction = UISwipeGestureRecognizerDirection.right
        swipeLeftGesture.direction = UISwipeGestureRecognizerDirection.left
        swipeView.addGestureRecognizer(swipeRightGesture)
        swipeView.addGestureRecognizer(swipeLeftGesture)
        
        // Pinch
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(gesture:)))
        pinchView.addGestureRecognizer(pinchGesture)
        
        // Rotate
        let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate(gesture:)))
        rotateView.addGestureRecognizer(rotateGesture)
        
    }
    
    // Tap action
    @objc func handleTap() {
        label.text = "Tap recognized"
        
        // example task: change background color
        if tapView.backgroundColor == UIColor.blue {
            tapView.backgroundColor = UIColor.red
        } else {
            tapView.backgroundColor = UIColor.blue
        }
        
    }
    
    // Double tap action
    @objc func handleDoubleTap() {
        label.text = "Double tap recognized"
        
        // example task: change background color
        if doubleTapView.backgroundColor == UIColor.yellow {
            doubleTapView.backgroundColor = UIColor.green
        } else {
            doubleTapView.backgroundColor = UIColor.yellow
        }
    }
    
    // Long press action
    @objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
        label.text = "Long press recognized"
        
        // example task: show an alert
        if gesture.state == UIGestureRecognizerState.began {
            let alert = UIAlertController(title: "Long Press", message: "Can I help you?", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    // Pan action
    @objc func handlePan(gesture: UIPanGestureRecognizer) {
        label.text = "Pan recognized"
        
        // example task: drag view
        let location = gesture.location(in: view) // root view
        panView.center = location
    }
    
    // Swipe action
    @objc func handleSwipe(gesture: UISwipeGestureRecognizer) {
        label.text = "Swipe recognized"
        
        // example task: animate view off screen
        let originalLocation = swipeView.center
        if gesture.direction == UISwipeGestureRecognizerDirection.right {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x += self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        } else if gesture.direction == UISwipeGestureRecognizerDirection.left {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x -= self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        }
    }
    
    // Pinch action
    @objc func handlePinch(gesture: UIPinchGestureRecognizer) {
        label.text = "Pinch recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(scaleX: gesture.scale, y: gesture.scale)
            pinchView.transform = transform
        }
    }
    
    // Rotate action
    @objc func handleRotate(gesture: UIRotationGestureRecognizer) {
        label.text = "Rotate recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(rotationAngle: gesture.rotation)
            rotateView.transform = transform
        }
    }
}

Remarques

  • Vous pouvez ajouter plusieurs reconnaisseurs de mouvements à une seule vue. Par souci de simplicité, cependant, je ne l'ai pas fait (sauf pour le geste de balayage). Si vous en avez besoin pour votre projet, vous devriez lire la documentation de reconnaissance des gestes . C'est assez compréhensible et utile.
  • Problèmes connus avec mes exemples ci-dessus: (1) La vue panoramique réinitialise son cadre lors du prochain événement gestuel. (2) La vue par balayage vient de la mauvaise direction lors du premier balayage. (Cependant, ces bogues dans mes exemples ne devraient pas affecter votre compréhension du fonctionnement des outils de reconnaissance des gestes.)
Suragch
la source
2
Votre réponse est vraiment agréable et utile avec une description détaillée. Et c'est pourquoi j'ai voté, vous répondez aussi. Mais vous venez de manquer une instruction que je pense que vous devez inclure dans votre réponse comme vous l'avez expliqué en détail. Cette instruction concerne la définition de "<yourView> .EnableUserInteraction = TRUE". J'espère que vous serez d'accord avec moi.
Euh. Vihar
3
Pour que cela fonctionne sur un, UIViewvous devez également ajouter:self.isUserInteractionEnabled = true;
neiker
52

Je pense que vous pouvez simplement utiliser

UIControl *headerView = ...
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

je veux dire headerView s'étend de UIControl.

LiCheng
la source
7
C'est la meilleure réponse. UITapGestureRecognizern'est pas un remplacement de UIControlEventTouchDown. Un Tapcompose généralement de UIControlEventTouchDownet UIControlEventTouchUpInside.
ohho
62
A UIViewn'est pas un UIControlet n'a donc pas accès à addTarget:action:forControlEvents:.
RobertJoseph
9
Notez également qu'un UIControl hérite de UIView. Pour mes besoins, tout ce que j'avais à faire était un simple commutateur de type sous-classe.
pretzels1337
1
vous pouvez définir sa classe sur UIControl @RobertJoseph .. Accédez au fichier xib et définissez la classe View Custom sur UIControl. maintenant vous pouvez gérer l'événement dedans ..
Zar E Ahmer
2
Alors pourquoi encore une meilleure solution puisque je change d'héritage juste pour gérer les taps?
Anthony Glyadchenko
21

Swift 3 et Swift 4

import UIKit

extension UIView {
  func addTapGesture(tapNumber: Int, target: Any, action: Selector) {
    let tap = UITapGestureRecognizer(target: target, action: action)
    tap.numberOfTapsRequired = tapNumber
    addGestureRecognizer(tap)
    isUserInteractionEnabled = true
  }
}

Utilisation

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))
Indrajit Sinh Rayjada
la source
Merci. Fonctionne très bien!
Mikrasya
1
Aime ça! Ajout à tous les projets;)
budidino
17

En fonction de la réponse acceptée, vous pouvez définir une macro:

#define handle_tap(view, delegate, selector) do {\
    view.userInteractionEnabled = YES;\
    [view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:delegate action:selector]];\
} while(0)

Cette macro utilise ARC, donc il n'y a pas d' releaseappel.

Exemple d'utilisation de macro:

handle_tap(userpic, self, @selector(onTapUserpic:));
rudyryk
la source
4
Si vous créez la vue dans le storyboard, n'oubliez pas d'activer l'option "interaction utilisateur activée".
david
où nous devons définir les macros en .h ou .m et quel devrait être le nom des paramètres. je veux dire #define handle_tap (vue UIView, délégué délégué, sélecteur SEL) faire ..
Zar E Ahmer
8

Vous pouvez y parvenir en ajoutant Gesture Recognizer dans votre code.

Étape 1: ViewController.m:

// Declare the Gesture.
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] 
                                          initWithTarget:self 
                                          action:@selector(handleTap:)];
gesRecognizer.delegate = self;

// Add Gesture to your view.
[yourView addGestureRecognizer:gesRecognizer]; 

Étape 2: ViewController.m:

// Declare the Gesture Recogniser handler method.
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer{
   NSLog(@"Tapped");
}

NOTE: ici yourView dans mon cas était @property (strong, nonatomic) IBOutlet UIView *localView;

EDIT: * localView est la boîte blanche dans Main.storyboard d'en bas

entrez la description de l'image ici

entrez la description de l'image ici

Annu
la source
j'ai plusieurs vues, puis-je l'identifiant de l'expéditeur?
Moin Shirazi
Vous devez aller dans la sous-vue intérieure, puis vous pouvez envoyer l'expéditeur .--------- pour (vue UIView * dans self.topicScrollView.subviews) {// Aller à l'intérieur de la vue d'ensemble si ([view isKindOfClass: [Classe UIButton]]) {// Aller à cette vue particulière // Ici, vous avez atteint ce point. }}
Annu
8

Dans Swift 4.2 et Xcode 10

Utilisez UITapGestureRecognizer pour ajouter un événement tactile

//Add tap gesture to your view
let tap = UITapGestureRecognizer(target: self, action: #selector(handleGesture))
yourView.addGestureRecognizer(tap)

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
//Write your code here
}

Si vous souhaitez utiliser SharedClass

//This is my shared class
import UIKit

class SharedClass: NSObject {

    static let sharedInstance = SharedClass()

    //Tap gesture function
    func addTapGesture(view: UIView, target: Any, action: Selector) {
        let tap = UITapGestureRecognizer(target: target, action: action)
        view.addGestureRecognizer(tap)
    }
} 

J'ai 3 vues dans mon ViewController appelées view1, view2 et view3.

override func viewDidLoad() {
    super.viewDidLoad()
    //Add gestures to your views
    SharedClass.sharedInstance.addTapGesture(view: view1, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view2, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view3, target: self, action: #selector(handleGesture2))

}

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
    print("printed 1&2...")
}
// GestureRecognizer
@objc func handleGesture2(gesture: UITapGestureRecognizer) -> Void {
    print("printed3...")
}
iOS
la source
6

Voici une version Swift:

// MARK: Gesture Extensions
extension UIView {

    func addTapGesture(#tapNumber: Int, target: AnyObject, action: Selector) {
        let tap = UITapGestureRecognizer (target: target, action: action)
        tap.numberOfTapsRequired = tapNumber
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }

    func addTapGesture(#tapNumber: Int, action: ((UITapGestureRecognizer)->())?) {
        let tap = BlockTap (tapCount: tapNumber, fingerCount: 1, action: action)
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }
}
Esqarrouth
la source
c'est quoi BlockTap?
He Yifei 何 一 非
1
Oh mec, j'ai oublié cette partie. C'est une fonction personnalisée. Ici: github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/…
Esqarrouth
5

Swift 3:

let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGestureRecognizer(_:)))
view.addGestureRecognizer(tapGestureRecognizer)

func handleTapGestureRecognizer(_ gestureRecognizer: UITapGestureRecognizer) {

}
Giang
la source
1

Cela semble assez simple de nos jours. Ceci est la version Swift.

let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
    view.addGestureRecognizer(tap)

@objc func viewTapped(recognizer: UIGestureRecognizer)
{
    //Do what you need to do!
}
daj mi spokój
la source
0

Voici la tapgesture ios; Vous devez d'abord créer une action pour GestureRecognizer après avoir écrit le code ci-dessous sous l'action comme indiqué ci-dessous

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}
sathish
la source
0

Une autre façon consiste à ajouter un bouton transparent à la vue

UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
b.frame = CGRectMake(0, 0, headerView.width, headerView.height);
[headerView addSubview:b];
[b addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchDown];

Et puis, gérez le clic:

- (void)buttonClicked:(id)sender
{}
thanhbinh84
la source
0

Créez un identificateur de gestes (sous-classe), qui implémentera des événements tactiles, comme touchesBegan. Vous pouvez ensuite l'ajouter à la vue.

De cette façon, vous utiliserez la composition à la place du sous-classement (ce qui était la demande).

Geri Borbás
la source
0

Pourquoi n'essayez-vous pas SSEventListener ?

Vous n'avez pas besoin de créer de reconnaissance de gestes et de séparer votre logique d'une autre méthode. SSEventListenerprend en charge la définition de blocs d'écoute sur une vue pour écouter les gestes simples, les gestes doubles et les gestes N-tap si vous le souhaitez, et les gestes de pression longue. La définition d'un écouteur de gestes à simple pression devient la suivante:

[view ss_addTapViewEventListener:^(UITapGestureRecognizer *recognizer) { ... } numberOfTapsRequired:1];

Shengsheng
la source
0

Objectif c:

UIControl *headerView = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

Rapide:

let headerView = UIControl(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: nextY))
headerView.addTarget(self, action: #selector(myEvent(_:)), for: .touchDown)

La question demande:

Comment ajouter un événement tactile à une UIView?

Il ne demande pas un événement de robinet .

Plus précisément, OP souhaite mettre en œuvre UIControlEventTouchDown

La commutation UIViewà UIControlest la bonne réponse ici parce que Gesture Recognisersje ne sais rien au sujet .touchDown, .touchUpInside,.touchUpOutside etc.

De plus, UIControl hérite d'UIView pour que vous ne perdiez aucune fonctionnalité.

Si tout ce que vous voulez est un robinet, vous pouvez utiliser le Gesture Recognizer. Mais si vous voulez un contrôle plus fin, comme cette question le demande, vous aurez besoin d'UIControl.

https://developer.apple.com/documentation/uikit/uicontrol?language=objc https://developer.apple.com/documentation/uikit/uigesturerecognizer?language=objc

janakmshah
la source