¿Cómo agregar un evento táctil a una UIView?

280

¿Cómo agrego un evento táctil a una UIView?
Lo intento:

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

No quiero crear una subclase y sobrescribir

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
Manni
fuente
Para Swift, puede obtenerlo desde aquí: stackoverflow.com/questions/28675209/…
Mr.Javed Multani

Respuestas:

578

En iOS 3.2 y versiones posteriores, puede usar reconocedores de gestos. Por ejemplo, así es como manejaría un evento de 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...
}

También hay un montón de gestos incorporados. Consulte los documentos para el manejo de eventos de iOS y UIGestureRecognizer. También tengo un montón de código de muestra en github que podría ayudar.

Nathan Eror
fuente
Pero eso está sobrescribiendo la acción táctil por defecto de la vista. ¿Es posible llamar a la acción táctil predeterminada de la vista? Algo así como [super touchesBegan]? ...
M Penades
2
¿Qué hace la línea CGPoint?
zakdances
2
@yourfriendzak CGPointrepresenta la ubicación del toque en la supervista de la vista girada. Puede usar este punto para mover la vista girada (o una vista hermana) a la ubicación girada. Esto es más útil en el controlador UIPanGestureRecognizerpara arrastrar la vista por la pantalla.
Nathan Eror
55
Gran respuesta concisa, gracias. pero caramba, ¿no sería bueno si esto fuera un poquito más fácil? :)
natbro
No está tan mal, pero desearía que hubiera una API basada en bloques como github.com/neror/ftutils/blob/master/Headers/FTUtils/… . Xcode 4 también tiene soporte para agregar / configurar reconocedores de gestos en Interface Builder.
Nathan Eror
126

Reconocedores de gestos

Hay una serie de eventos táctiles (o gestos) de uso común que se le pueden notificar cuando agrega un Reconocimiento de gestos a su vista. Los siguientes tipos de gestos son compatibles de forma predeterminada:

  • UITapGestureRecognizer Toque (tocar la pantalla brevemente una o más veces)
  • UILongPressGestureRecognizer Toque largo (tocar la pantalla durante mucho tiempo)
  • UIPanGestureRecognizer Pan (moviendo el dedo por la pantalla)
  • UISwipeGestureRecognizer Deslizar (mover el dedo rápidamente)
  • UIPinchGestureRecognizer Pellizcar (mover dos dedos juntos o separados, generalmente para hacer zoom)
  • UIRotationGestureRecognizer Rotar (mover dos dedos en dirección circular)

Además de estos, también puede hacer su propio reconocedor de gestos personalizado.

Agregar un gesto en el generador de interfaces

Arrastre un reconocedor de gestos desde la biblioteca de objetos a su vista.

ingrese la descripción de la imagen aquí

Controle el arrastre desde el gesto en el Esquema del documento hasta el código de su Controlador de vista para hacer una salida y una acción.

ingrese la descripción de la imagen aquí

Esto debe establecerse de manera predeterminada, pero también asegúrese de que la Acción del usuario habilitada esté establecida en verdadero para su vista.

ingrese la descripción de la imagen aquí

Agregar un gesto mediante programación

Para agregar un gesto mediante programación, usted (1) crea un reconocedor de gestos, (2) lo agrega a una vista y (3) crea un método que se llama cuando se reconoce el gesto.

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

Notas

  • El senderparámetro es opcional. Si no necesita una referencia al gesto, puede omitirlo. Sin embargo, si lo hace, elimine el(sender:) nombre del método después de la acción.
  • La denominación del handleTapmétodo fue arbitraria. Nómbralo como quieras usar .action: #selector(someMethodName(sender:))

Más ejemplos

Puede estudiar los reconocedores de gestos que agregué a estas vistas para ver cómo funcionan.

ingrese la descripción de la imagen aquí

Aquí está el código para ese proyecto:

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

Notas

  • Puede agregar múltiples reconocedores de gestos a una sola vista. Sin embargo, por simplicidad, no hice eso (excepto por el gesto de deslizar). Si lo necesita para su proyecto, debe leer la documentación del reconocedor de gestos . Es bastante comprensible y útil.
  • Problemas conocidos con mis ejemplos anteriores: (1) La vista panorámica restablece su marco en el siguiente evento de gesto. (2) La vista de deslizamiento proviene de la dirección incorrecta en el primer deslizamiento. (Sin embargo, estos errores en mis ejemplos no deberían afectar su comprensión de cómo funcionan los reconocedores de gestos).
Suragch
fuente
2
Su respuesta es realmente agradable y útil con una descripción detallada. Y es por eso que tengo que votar, tú también respondes. Pero acabas de perder una instrucción que creo que debes incluir en tu respuesta, ya que la has explicado con todo detalle. Esa instrucción se trata de configurar "<yourView> .EnableUserInteraction = TRUE". Espero que estés de acuerdo conmigo.
Er. Vihar
3
Para que esto funcione, UIViewtambién debe agregar:self.isUserInteractionEnabled = true;
neiker
52

Creo que simplemente puedes usar

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

Me refiero a headerView se extiende desde UIControl.

LiCheng
fuente
77
Esta es la mejor respuesta. UITapGestureRecognizerno es un sustituto de UIControlEventTouchDown. A Tapgeneralmente se compone de UIControlEventTouchDowny UIControlEventTouchUpInside.
ohho
62
A UIViewno es a UIControly por lo tanto no tiene acceso a addTarget:action:forControlEvents:.
RobertJoseph
9
También tenga en cuenta que un UIControl hereda de UIView. Para mis propósitos, todo lo que tenía que hacer era un simple cambio de tipo de subclase.
pretzels1337
1
puede establecer su clase en UIControl @RobertJoseph .. Vaya al archivo xib y configure la clase View Custom en UIControl. ahora puede manejar el evento en él ..
Zar E Ahmer
2
Entonces, ¿por qué esta es una mejor solución nuevamente ya que estoy cambiando la herencia solo para manejar grifos?
Anthony Glyadchenko
21

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

Utilizar

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))
Indrajit Sinh Rayjada
fuente
Gracias. ¡Funciona genial!
Mikrasya
1
¡Me gusta esto! Agregando a todos los proyectos;)
budidino
17

Según la respuesta aceptada , puede definir una macro:

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

Esta macro usa ARC, por lo que no hay releasellamada.

Ejemplo de uso de macro:

handle_tap(userpic, self, @selector(onTapUserpic:));
Rudyryk
fuente
44
Si crea la vista en el guión gráfico, no olvide habilitar la opción "interacción con el usuario habilitada".
David
donde deberíamos definir macros en .h o .m y cuál debería ser el nombre de los parámetros. Me refiero a #define handle_tap (vista UIView, delegado delegado, selector SEL) hacer ..
Zar E Ahmer
8

Puede lograr esto agregando Gesture Recognizer en su código.

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

Paso 2: ViewController.m:

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

NOTA: aquí yourView en mi caso fue @property (strong, nonatomic) IBOutlet UIView *localView;

EDITAR: * localView es el cuadro blanco en Main.storyboard desde abajo

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Annu
fuente
Tengo varias vistas, ¿puedo ver el id del remitente?
Moin Shirazi
Debe ir a la subvista interna, luego puede pagar al remitente .--------- for (UIView * view in self.topicScrollView.subviews) {// Ir dentro de la supervista if ([view isKindOfClass: [Clase UIButton]]) {// Vaya a esa vista en particular // Aquí ha llegado hasta ese punto. }}
Annu
8

En Swift 4.2 y Xcode 10

Use UITapGestureRecognizer para agregar un evento táctil

//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 quieres usar 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)
    }
} 

Tengo 3 vistas en mi ViewController llamadas view1, view2 y 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
fuente
6

Heres una versión 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
fuente
lo que es BlockTap?
Él Yifei 何 一 非
1
Oh hombre, olvidé esa parte. Es una función personalizada. Aquí: 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
fuente
1

Parece bastante simple en estos días. Esta es la versión 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
fuente
0

Aquí está ios tapgesture; Primero debe crear una acción para GestureRecognizer después de escribir el siguiente código debajo de la acción como se muestra a continuación

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}
sathish
fuente
0

Otra forma es agregar un botón transparente a la 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];

Y luego, maneja el clic:

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

Cree un reconocedor de gestos (subclase), que implementará eventos táctiles, como touchesBegan. Puede agregarlo a la vista después de eso.

De esta forma, usará la composición en lugar de subclases (que era la solicitud).

Geri Borbás
fuente
0

¿Por qué no prueban SSEventListener ?

No necesita crear ningún reconocedor de gestos y separar su lógica de otro método. SSEventListeneradmite la configuración de bloques de escucha en una vista para escuchar el gesto de un solo toque, el gesto de doble toque y el gesto de N-toque si lo desea, y el gesto de pulsación larga. Configurar un oyente de gestos de un solo toque se convierte de esta manera:

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

Shengsheng
fuente
0

C objetivo:

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

Rápido:

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

¿Cómo agrego un evento táctil a una UIView?

No está pidiendo un evento de tap .

Específicamente OP quiere implementar UIControlEventTouchDown

Cambio de la UIViewque UIControles la respuesta correcta aquí porque Gesture Recognisersno se sabe nada acerca de .touchDown, .touchUpInside,.touchUpOutside etc.

Además, UIControl hereda de UIView para que no pierda ninguna funcionalidad.

Si todo lo que desea es un toque, puede usar el Reconocimiento de gestos. Pero si desea un control más preciso, como se hace en esta pregunta, necesitará UIControl.

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

janakmshah
fuente