Come aggiungere un evento touch a un UIView?


280

Come faccio ad aggiungere un evento touch a un UIView?
Provo:

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:'

Non voglio creare una sottoclasse e sovrascriverla

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

Per rapido si può ottenere da qui: stackoverflow.com/questions/28675209/...
Mr.Javed Multani

Risposte:


578

In iOS 3.2 e versioni successive, puoi utilizzare i riconoscitori di gesti. Ad esempio, è così che gestiresti un evento 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...
}

Ci sono anche molti gesti integrati. Consulta i documenti per la gestione degli eventi iOS e UIGestureRecognizer. Ho anche un sacco di codice di esempio su github che potrebbe aiutare.


Ma questo è sovrascrivere il tocco senza azione della vista. ¿È possibile chiamare l'azione touch predefinita della vista? Qualcosa come [super touchesBegan]? ...
M Penades,

2
Cosa fa la linea CGPoint?
zakdances,

2
@yourfriendzak the CGPointrappresenta la posizione del rubinetto nella superview della vista toccata. È possibile utilizzare questo punto per spostare la vista toccata (o una vista fratello) nella posizione toccata. Questo è più utile nel gestore per a UIPanGestureRecognizerper trascinare la vista sullo schermo.
Nathan Eror,

5
ottima risposta concisa, grazie. ma, non sarebbe bello se questo fosse un pochino più facile ?! :)
natbro,

Non è poi così male, ma vorrei che esistesse un'API basata su blocchi come github.com/neror/ftutils/blob/master/Headers/FTUtils/… . Xcode 4 supporta anche l'aggiunta / configurazione di riconoscitori di gesti in Interface Builder.
Nathan Eror,

126

Riconoscitori di gesti

Esistono numerosi eventi (o gesti) di tocco comunemente utilizzati di cui è possibile ricevere notifiche quando si aggiunge un Riconoscimento gesti alla vista. I seguenti tipi di gesti sono supportati per impostazione predefinita:

  • UITapGestureRecognizer Tocca (toccando brevemente lo schermo una o più volte)
  • UILongPressGestureRecognizer Tocco lungo (toccando lo schermo per molto tempo)
  • UIPanGestureRecognizer Pan (muovendo il dito sullo schermo)
  • UISwipeGestureRecognizer Scorri (muovendo rapidamente il dito)
  • UIPinchGestureRecognizer Pizzica (muovendo due dita insieme o separatamente - di solito per ingrandire)
  • UIRotationGestureRecognizer Ruota (muovendo due dita in una direzione circolare)

Oltre a questi, puoi anche creare il tuo riconoscimento gesti personalizzato.

Aggiunta di un gesto nel Interface Builder

Trascina un riconoscimento gesti dalla libreria degli oggetti sulla tua vista.

inserisci qui la descrizione dell'immagine

Controlla il trascinamento dal gesto nella Struttura del documento al codice del tuo View Controller per creare un Outlet e un'azione.

inserisci qui la descrizione dell'immagine

Questo dovrebbe essere impostato di default, ma assicurati anche che User Action Enabled sia impostato su true per la tua vista.

inserisci qui la descrizione dell'immagine

Aggiunta di un gesto a livello di codice

Per aggiungere un gesto a livello di codice, è necessario (1) creare un riconoscimento gesti, (2) aggiungerlo a una vista e (3) creare un metodo che viene chiamato quando il gesto viene riconosciuto.

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")
    }
}

Appunti

  • Il senderparametro è facoltativo Se non hai bisogno di un riferimento al gesto, puoi lasciarlo fuori. In tal caso, tuttavia, rimuovere il(sender:) nome del metodo di azione dopo.
  • La denominazione del handleTapmetodo era arbitraria. Denominalo come preferisci .action: #selector(someMethodName(sender:))

Altri esempi

Puoi studiare i riconoscitori di gesti che ho aggiunto a queste viste per vedere come funzionano.

inserisci qui la descrizione dell'immagine

Ecco il codice per quel progetto:

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
        }
    }
}

Appunti

  • È possibile aggiungere più riconoscitori di gesti a una singola vista. Per semplicità, tuttavia, non l'ho fatto (tranne per il gesto di scorrimento). Se è necessario per il progetto, è necessario leggere la documentazione del riconoscimento gesti . È abbastanza comprensibile e utile.
  • Problemi noti con i miei esempi precedenti: (1) La vista panoramica reimposta la sua cornice al prossimo evento di gesto. (2) La vista a scorrimento proviene dalla direzione sbagliata al primo colpo. (Questi bug nei miei esempi non dovrebbero influenzare la tua comprensione di come funzionano i Riconoscitori di gesti.)

2
La tua risposta è davvero piacevole e utile con una descrizione dettagliata. Ed è per questo che ho votato fino a rispondere anche tu. Ma hai appena perso un'istruzione che penso tu debba includere nella tua risposta come l'hai spiegata in dettaglio. Quell'istruzione riguarda l'impostazione "<yourView> .EnableUserInteraction = TRUE". Spero che tu sia d'accordo con me.
Er. Vihar,

3
Per far funzionare questo su un UIViewdevi aggiungere anche:self.isUserInteractionEnabled = true;
neiker

52

Penso che tu possa semplicemente usare

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

intendo headerView si estende da UIControl.


7
Questa è la risposta migliore UITapGestureRecognizernon è un sostituto di UIControlEventTouchDown. A di Tapsolito è composto da UIControlEventTouchDowne UIControlEventTouchUpInside.
oh,

62
A UIViewnon è a UIControle quindi non ha accesso a addTarget:action:forControlEvents:.
Robert Joseph

9
Si noti inoltre che un UIControl eredita da UIView. Per i miei scopi tutto quello che dovevo fare era un semplice passaggio di tipo sottoclasse.
pretzels1337,

1
puoi impostare la sua classe su UIControl @RobertJoseph .. Vai al file xib e imposta la classe Visualizza personalizzata su UIControl. ora puoi gestire l'evento in esso ..
Zar E Ahmer,

2
Quindi perché questa è di nuovo una soluzione migliore dal momento che sto cambiando l'eredità solo per gestire i tocchi?
Anthony Glyadchenko,

21

Swift 3 e 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
  }
}

Uso

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))

Grazie. Funziona alla grande!
Mikrasya,

1
Ama questo! Aggiungendo a tutti i progetti;)
budidino,

17

In base alla risposta accettata è possibile definire una macro:

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

Questa macro usa ARC, quindi non c'è releasechiamata.

Esempio di utilizzo di macro:

handle_tap(userpic, self, @selector(onTapUserpic:));

4
Se crei la vista nello storyboard, non dimenticare di abilitare l'opzione "Interazione utente abilitata".
david

dove dovremmo definire le macro in .h o .m e quale dovrebbe essere il nome dei parametri. intendo #define handle_tap (vista UIView, delegato delegato, selettore SEL) do ..
Zar E Ahmer,

8

Puoi farlo aggiungendo Gesture Recogniser nel tuo codice.

Passaggio 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]; 

Passaggio 2: ViewController.m:

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

NOTA: qui il tuo View nel mio caso era @property (strong, nonatomic) IBOutlet UIView *localView;

EDIT: * localView è la casella bianca in Main.storyboard dal basso

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


sto avendo una visualizzazione multipla, quindi posso l'ID mittente ??
Moin Shirazi,

Devi andare alla sottoview interna, quindi puoi mettere in pausa il mittente .--------- per (vista UIView * in self.topicScrollView.subviews) {// Vai all'interno della superview se ([view isKindOfClass: [UIButton class]]) {// Vai a quella vista particolare // Qui sei arrivato fino a quel punto. }}
Annu,

8

In Swift 4.2 e Xcode 10

Usa UITapGestureRecognizer per aggiungere un evento touch

//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
}

Se si desidera utilizzare 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)
    }
} 

Ho 3 visualizzazioni nel mio ViewController chiamato view1, view2 e 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...")
}

6

Ecco una versione 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
    }
}

che cos'è BlockTap?
He Yifei

1
Oh amico, ho dimenticato quella parte. È una funzione personalizzata. Qui: 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) {

}

1

Sembra abbastanza semplice in questi giorni. Questa è la versione Swift.

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

@objc func viewTapped(recognizer: UIGestureRecognizer)
{
    //Do what you need to do!
}

0

Ecco ios tapgesture; Per prima cosa devi creare un'azione per GestureRecognizer dopo aver scritto il codice seguente sotto l'azione come mostrato di seguito

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}

0

Un altro modo è l'aggiunta di un pulsante trasparente alla vista

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];

E poi, gestisci clic:

- (void)buttonClicked:(id)sender
{}

0

Crea un riconoscimento dei gesti (sottoclasse), che implementerà eventi tattili, come touchesBegan . Successivamente puoi aggiungerlo alla vista.

In questo modo utilizzerai la composizione anziché la sottoclasse (che era la richiesta).


0

Perché non provate SSEventListener ?

Non è necessario creare alcun riconoscimento dei gesti e separare la logica da un altro metodo. SSEventListenersupporta l'impostazione di blocchi di listener in una vista per ascoltare il gesto del tocco singolo, il gesto del doppio tocco e il gesto del tocco N, se lo desideri, e il gesto della pressione prolungata. L'impostazione di un listener di gesti con un solo tocco diventa così:

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


0

Objective-C:

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

Swift:

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 domanda pone:

Come faccio ad aggiungere un evento touch a un UIView?

Non sta chiedendo un tocco evento .

Nello specifico OP vuole implementare UIControlEventTouchDown

Commutazione della UIViewa UIControlè la risposta giusta qui perché Gesture Recognisersnon so nulla .touchDown, .touchUpInside,.touchUpOutside etc.

Inoltre, UIControl eredita da UIView in modo da non perdere alcuna funzionalità.

Se tutto ciò che desideri è un tocco, puoi utilizzare il Gesture Recogniser. Ma se vuoi un controllo più preciso, come questa domanda richiede, avrai bisogno di UIControl.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.