UIGestureRecognizer en UIImageView

179

tengo un UIImageView , que quiero poder cambiar el tamaño y rotar, etc.

¿Se UIGestureRecognizerpuede agregar a UIImageView?

Me gustaría agregar un reconocedor de rotación y pellizco a uno UIImageViewque se crearía en tiempo de ejecución.

¿Cómo se agregan estos reconocedores?

sistema
fuente

Respuestas:

426

Comprueba que userInteractionEnabledestá YESen el UIImageView. Luego puede agregar un reconocedor de gestos.

imageView.userInteractionEnabled = YES;
UIPinchGestureRecognizer *pgr = [[UIPinchGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handlePinch:)];
pgr.delegate = self;
[imageView addGestureRecognizer:pgr];
[pgr release];
:
:
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
  //handle pinch...
}
Abubakr Dar
fuente
55
No, esto solo muestra cómo agregar los reconocedores de gestos. Tienes que hacer el zoom / rotar tú mismo en los manejadores de gestos. Vea la aplicación de ejemplo Touches_GestureRecognizers sobre cómo hacer el zoom / rotar.
77
+1 se sentó aquí durante años tratando de descubrir por qué mis gestos no funcionarían ... "Compruebe que userInteractionEnabled es SÍ en el UIImageView". ¡Gracias!
Critter
1
Esto definitivamente hizo que mi trabajo fuera más fácil que tratar de establecer límites en un conjunto de reconocimiento para la vista general. ¡Gracias!
Josh Kovach
66
imageView.userInteractionEnabled = YES; esta es la clave! Gracias.
HamasN
3
userInteractionEnabledtodavía debe establecerse en YES / true en Xcode 8 Objective-C / Swift
leanne
76

Sí, se puede agregar un UIGestureRecognizer a un UIImageView. Como se indicó en la otra respuesta, es muy importante recordar habilitar la interacción del usuario en la vista de imagen estableciendo su userInteractionEnabledpropiedad en YES. UIImageView hereda de UIView, cuya propiedad de interacción de usuario está configurada YESde manera predeterminada, sin embargo, la propiedad de interacción de usuario de UIImageView está configurada NOde manera predeterminada.

De los documentos UIImageView:

Los nuevos objetos de vista de imagen están configurados para ignorar los eventos del usuario de forma predeterminada. Si desea manejar eventos en una subclase personalizada de UIImageView, debe cambiar explícitamente el valor de la propiedad userInteractionEnabled a YES después de inicializar el objeto.

De todos modos, en la mayor parte de la respuesta. Aquí hay un ejemplo de cómo crear un UIImageViewcon a UIPinchGestureRecognizer, a UIRotationGestureRecognizery a UIPanGestureRecognizer.

Primero, en viewDidLoadu otro método de su elección, cree una vista de imagen, dele una imagen, un marco y permita su interacción con el usuario. Luego crea los tres gestos de la siguiente manera. Asegúrese de utilizar su propiedad delegada (muy probablemente configurada como self). Esto será necesario para usar múltiples gestos al mismo tiempo.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // set up the image view
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImage"]];
    [imageView setBounds:CGRectMake(0.0, 0.0, 120.0, 120.0)];
    [imageView setCenter:self.view.center];
    [imageView setUserInteractionEnabled:YES]; // <--- This is very important

    // create and configure the pinch gesture
    UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureDetected:)];
    [pinchGestureRecognizer setDelegate:self];
    [imageView addGestureRecognizer:pinchGestureRecognizer];

    // create and configure the rotation gesture
    UIRotationGestureRecognizer *rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGestureDetected:)];
    [rotationGestureRecognizer setDelegate:self];
    [imageView addGestureRecognizer:rotationGestureRecognizer];

    // creat and configure the pan gesture
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureDetected:)];
    [panGestureRecognizer setDelegate:self];
    [imageView addGestureRecognizer:panGestureRecognizer];


    [self.view addSubview:imageView]; // add the image view as a subview of the view controllers view
}

Estos son los tres métodos que se llamarán cuando se detecten los gestos en su vista. Dentro de ellos, verificaremos el estado actual del gesto, y si está en el inicio o el cambioUIGestureRecognizerState , leeremos la propiedad de escala / rotación / traducción del gesto, aplicaremos esos datos a una transformación afín, aplicaremos la transformación afín a la imagen. ver, y luego restablecer la escala de gestos / rotación / traducción.

- (void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGFloat scale = [recognizer scale];
        [recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
        [recognizer setScale:1.0];
    }
}

- (void)rotationGestureDetected:(UIRotationGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGFloat rotation = [recognizer rotation];
        [recognizer.view setTransform:CGAffineTransformRotate(recognizer.view.transform, rotation)];
        [recognizer setRotation:0];
    }
}

- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGPoint translation = [recognizer translationInView:recognizer.view];
        [recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
        [recognizer setTranslation:CGPointZero inView:recognizer.view];
    }
}

Finalmente y muy importante, necesitará utilizar el método UIGestureRecognizerDelegategestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer para permitir que los gestos funcionen al mismo tiempo. Si estos tres gestos son los únicos tres gestos que tienen esta clase asignada como su delegado, simplemente puede regresarYES como se muestra a continuación. Sin embargo, si tiene gestos adicionales que tienen esta clase asignada como su delegado, es posible que deba agregar lógica a este método para determinar qué gesto es cuál antes de permitir que todos trabajen juntos.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

No olvide asegurarse de que su clase cumpla con el protocolo UIGestureRecognizerDelegate . Para hacerlo, asegúrese de que su interfaz se vea así:

@interface MyClass : MySuperClass <UIGestureRecognizerDelegate>

Si prefiere jugar con el código en un proyecto de muestra en funcionamiento, puede encontrar el proyecto de muestra que he creado que contiene este código aquí.

Mick MacCallum
fuente
1
Esta es, con mucho, la mejor respuesta que he visto en stackoverflow.com, detallada, bien comentada e incluso incluye código fuente en git. Gracias por eso
Alejandro Luengo
1
Claro, paso a paso, explicación increíble
Alvin
1
Gracias, eso hizo en una o dos páginas lo que varias docenas de tutoriales durante años de Apple y otros no pudieron hacer. Siento que debe haber muchas otras cosas en iOS que son posibles, pero debido a la ofuscación y la incomprensión, nos hemos perdido.
Zack Morris
Gran respuesta, la mejor. Muchas gracias por tu paciencia.
Jorg B Jorge
13

Swift 4.2

myImageView.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
tapGestureRecognizer.numberOfTapsRequired = 1
myImageView.addGestureRecognizer(tapGestureRecognizer)

y cuando se toca:

@objc func imageTapped(_ sender: UITapGestureRecognizer) {
   // do something when image tapped
   print("image tapped")
}
ayalcinkaya
fuente
11

Solución Swift 2.0

Crea un reconocedor de gestos de tocar, pellizcar o deslizar en la misma mansión. A continuación, lo guiaré a través de 4 pasos para poner en marcha su reconocedor.

4 pasos

1.) Herede de UIGestureRecognizerDelegateagregarlo a la firma de su clase.

class ViewController: UIViewController, UIGestureRecognizerDelegate {...}

2.) Controle el arrastre de su imagen a su viewController para crear un IBOutlet:

@IBOutlet weak var tapView: UIImageView!

3.) En su viewDidLoad agregue el siguiente código:

// create an instance of UITapGestureRecognizer and tell it to run 
// an action we'll call "handleTap:"
let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
// we use our delegate
tap.delegate = self
// allow for user interaction
tapView.userInteractionEnabled = true
// add tap as a gestureRecognizer to tapView
tapView.addGestureRecognizer(tap)

4.) Cree la función que se llamará cuando toque su reconocedor de gestos. (Puede excluir el = nilsi lo desea).

func handleTap(sender: UITapGestureRecognizer? = nil) {
    // just creating an alert to prove our tap worked!
    let tapAlert = UIAlertController(title: "hmmm...", message: "this actually worked?", preferredStyle: UIAlertControllerStyle.Alert)
    tapAlert.addAction(UIAlertAction(title: "OK", style: .Destructive, handler: nil))
    self.presentViewController(tapAlert, animated: true, completion: nil)
}

Su código final debería verse así:

class ViewController: UIViewController, UIGestureRecognizerDelegate {

    @IBOutlet weak var tapView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
        tap.delegate = self
        tapView.userInteractionEnabled = true
        tapView.addGestureRecognizer(tap)
    }

    func handleTap(sender: UITapGestureRecognizer? = nil) {
        let tapAlert = UIAlertController(title: "hmmm...", message: "this actually worked?", preferredStyle: UIAlertControllerStyle.Alert)
        tapAlert.addAction(UIAlertAction(title: "OK", style: .Destructive, handler: nil))
        self.presentViewController(tapAlert, animated: true, completion: nil)
    }
}
Dan Beaulieu
fuente
1
escribí un blog sobre esto aquí: codebeaulieu.com/3/UIGestureRecognier-programatic
Dan Beaulieu
6

Acabo de hacer esto con swift4 agregando 3 gestos juntos en una sola vista

  1. UIPinchGestureRecognizer : acercar y alejar la vista.
  2. UIRotationGestureRecognizer : gira la vista.
  3. UIPanGestureRecognizer : arrastrando la vista.

Aquí mi código de muestra

class ViewController: UIViewController: UIGestureRecognizerDelegate{
      //your image view that outlet from storyboard or xibs file.
     @IBOutlet weak var imgView: UIImageView!
     // declare gesture recognizer
     var panRecognizer: UIPanGestureRecognizer?
     var pinchRecognizer: UIPinchGestureRecognizer?
     var rotateRecognizer: UIRotationGestureRecognizer?

     override func viewDidLoad() {
          super.viewDidLoad()
          // Create gesture with target self(viewcontroller) and handler function.  
          self.panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(recognizer:)))
          self.pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(self.handlePinch(recognizer:)))
          self.rotateRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(self.handleRotate(recognizer:)))
          //delegate gesture with UIGestureRecognizerDelegate
          pinchRecognizer?.delegate = self
          rotateRecognizer?.delegate = self
          panRecognizer?.delegate = self
          // than add gesture to imgView
          self.imgView.addGestureRecognizer(panRecognizer!)
          self.imgView.addGestureRecognizer(pinchRecognizer!)
          self.imgView.addGestureRecognizer(rotateRecognizer!)
     }

     // handle UIPanGestureRecognizer 
     @objc func handlePan(recognizer: UIPanGestureRecognizer) {    
          let gview = recognizer.view
          if recognizer.state == .began || recognizer.state == .changed {
               let translation = recognizer.translation(in: gview?.superview)
               gview?.center = CGPoint(x: (gview?.center.x)! + translation.x, y: (gview?.center.y)! + translation.y)
               recognizer.setTranslation(CGPoint.zero, in: gview?.superview)
          }
     }

     // handle UIPinchGestureRecognizer 
     @objc func handlePinch(recognizer: UIPinchGestureRecognizer) {
          if recognizer.state == .began || recognizer.state == .changed {
               recognizer.view?.transform = (recognizer.view?.transform.scaledBy(x: recognizer.scale, y: recognizer.scale))!
               recognizer.scale = 1.0
         }
     }   

     // handle UIRotationGestureRecognizer 
     @objc func handleRotate(recognizer: UIRotationGestureRecognizer) {
          if recognizer.state == .began || recognizer.state == .changed {
               recognizer.view?.transform = (recognizer.view?.transform.rotated(by: recognizer.rotation))!
               recognizer.rotation = 0.0
           }
     }

     // mark sure you override this function to make gestures work together 
     func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
         return true
     }

}

Cualquier pregunta, solo escribe para comentar. gracias

Leang Socheat
fuente
3

SWIFT 3 Ejemplo

override func viewDidLoad() {

    self.backgroundImageView.addGestureRecognizer(
        UITapGestureRecognizer.init(target: self, action:#selector(didTapImageview(_:)))
    )

    self.backgroundImageView.isUserInteractionEnabled = true
}

func didTapImageview(_ sender: Any) {
    // do something
}

No hay delegados de reconocimiento de gestos u otras implementaciones cuando sea necesario.

Mourodrigo
fuente
2

También puede arrastrar un reconocedor de gestos de toque a la vista de imagen en Storyboard. Luego crea una acción por ctrl + dragel código.

zevij
fuente
1

Para el amante de los bloques, puede usar ALActionBlocks para agregar acción de gestos en el bloque

__weak ALViewController *wSelf = self;
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithBlock:^(UITapGestureRecognizer *weakGR) {
    NSLog(@"pan %@", NSStringFromCGPoint([weakGR locationInView:wSelf.view]));
}];
[self.imageView addGestureRecognizer:gr];
dimo hamdy
fuente