UIGestureRecognizer sur UIImageView

179

J'ai un UIImageView, que je veux pouvoir redimensionner et faire pivoter, etc.

Un peut-il UIGestureRecognizerêtre ajouté au UIImageView?

Je voudrais ajouter un outil de reconnaissance de rotation et de pincement à un UIImageViewqui serait créé au moment de l'exécution.

Comment ajouter ces outils de reconnaissance?

système
la source

Réponses:

426

Vérifiez que userInteractionEnabledc'est YESsur le UIImageView. Ensuite, vous pouvez ajouter un outil de reconnaissance de gestes.

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
la source
5
Non, cela montre simplement comment ajouter les outils de reconnaissance de gestes. Vous devez effectuer vous-même le zoom / la rotation dans les gestionnaires de gestes. Consultez l'exemple d'application Touches_GestureRecognizers pour savoir comment faire le zoom / la rotation.
77
+1 s'est assis ici pendant des lustres pour essayer de comprendre pourquoi mes gestes ne fonctionneraient pas. "Vérifiez que userInteractionEnabled est OUI sur UIImageView." Merci!
Critter
1
Cela a définitivement rendu mon travail plus facile que d'essayer de définir des limites sur un module de reconnaissance défini sur la vue globale. Merci!
Josh Kovach
6
imageView.userInteractionEnabled = OUI; c'est la clé! Je vous remercie.
HamasN
3
userInteractionEnableddoit toujours être réglé sur YES / true dans Xcode 8 Objective-C / Swift
leanne
76

Oui, un UIGestureRecognizer peut être ajouté à un UIImageView. Comme indiqué dans l'autre réponse, il est très important de ne pas oublier d'activer l'interaction de l'utilisateur sur la vue d'image en définissant sa userInteractionEnabledpropriété sur YES. UIImageView hérite de UIView, dont la propriété d'interaction utilisateur est définie YESpar défaut, cependant, la propriété d'interaction utilisateur d'UIImageView est définie surNO par défaut.

À partir de la documentation UIImageView:

Les nouveaux objets de vue d'image sont configurés pour ignorer les événements utilisateur par défaut. Si vous souhaitez gérer des événements dans une sous-classe personnalisée de UIImageView, vous devez explicitement modifier la valeur de la propriété userInteractionEnabled sur YES après l'initialisation de l'objet.

Quoi qu'il en soit, sur l'essentiel de la réponse. Voici un exemple de création d'un UIImageViewavec a UIPinchGestureRecognizer, a UIRotationGestureRecognizeret a UIPanGestureRecognizer.

Tout d'abord, dans viewDidLoadou dans une autre méthode de votre choix, créez une vue d'image, donnez-lui une image, un cadre et activez son interaction avec l'utilisateur. Créez ensuite les trois gestes comme suit. Assurez-vous d'utiliser leur propriété de délégué (probablement définie sur self). Cela sera nécessaire pour utiliser plusieurs gestes en même temps.

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

Voici les trois méthodes qui seront appelées lorsque les gestes de votre vue seront détectés. À l'intérieur, nous vérifierons l'état actuel du geste, et s'il est au début ou à la modification, UIGestureRecognizerStatenous lirons la propriété d'échelle / rotation / translation du geste, appliquerons ces données à une transformation affine, appliquerons la transformation affine à l'image vue, puis réinitialisez l'échelle / rotation / translation des gestes.

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

Enfin et surtout, vous devrez utiliser la méthode UIGestureRecognizerDelegategestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer pour permettre aux gestes de fonctionner en même temps. Si ces trois gestes sont les trois seuls gestes auxquels cette classe est attribuée comme délégué, vous pouvez simplement revenir YEScomme indiqué ci-dessous. Toutefois, si vous avez des gestes supplémentaires auxquels cette classe est attribuée comme délégué, vous devrez peut-être ajouter une logique à cette méthode pour déterminer quel geste est lequel avant de leur permettre de tous travailler ensemble.

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

N'oubliez pas de vous assurer que votre classe est conforme au protocole UIGestureRecognizerDelegate . Pour ce faire, assurez-vous que votre interface ressemble à ceci:

@interface MyClass : MySuperClass <UIGestureRecognizerDelegate>

Si vous préférez jouer vous-même avec le code d'un exemple de projet fonctionnel, l'exemple de projet que j'ai créé contenant ce code est disponible ici.

Mick MacCallum
la source
1
C'est de loin la meilleure réponse que j'ai jamais vue sur stackoverflow.com, très détaillée, bien commentée et inclut même le code source sur git. Merci pour ça
Alejandro Luengo
1
Explication claire, étape par étape, géniale
Alvin
1
Merci d'avoir fait en une page ou deux ce que plusieurs dizaines de tutoriels au fil des ans d'Apple et d'autres n'ont pas réussi à faire. Je pense qu'il doit y avoir beaucoup d'autres choses dans iOS qui sont possibles, mais en raison de l'obscurcissement et du malentendu, elles nous sont perdues.
Zack Morris
Excellente réponse, la meilleure. Merci beaucoup pour votre patience.
Jorg B Jorge
13

Swift 4.2

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

et une fois tapé:

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

Solution Swift 2.0

Vous créez un outil de reconnaissance de gestes tapotement, pincement ou glissement dans le même manoir. Ci-dessous, je vais vous guider à travers 4 étapes pour que votre reconnaissance soit opérationnelle.

4 étapes

1.) Héritez de UIGestureRecognizerDelegateen l'ajoutant à votre signature de classe.

class ViewController: UIViewController, UIGestureRecognizerDelegate {...}

2.) Contrôlez le glisser de votre image vers votre viewController pour créer un IBOutlet:

@IBOutlet weak var tapView: UIImageView!

3.) Dans votre viewDidLoad, ajoutez le code suivant:

// 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.) Créez la fonction qui sera appelée lorsque votre reconnaissance de gestes est activée. (Vous pouvez exclure le = nilsi vous choisissez).

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

Votre code final devrait ressembler à ceci:

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
la source
1
J'ai écrit un blog à ce sujet ici: codebeaulieu.com/3/UIGestureRecognier-programately
Dan Beaulieu
6

Je viens de faire cela avec swift4 en ajoutant 3 gestes ensemble en vue unique

  1. UIPinchGestureRecognizer : Zoom avant et zoom arrière.
  2. UIRotationGestureRecognizer : faites pivoter la vue.
  3. UIPanGestureRecognizer : faites glisser la vue.

Voici mon exemple de code

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
     }

}

N'importe quelle question, tapez simplement pour commenter. Merci

Leang Socheat
la source
3

Exemple SWIFT 3

override func viewDidLoad() {

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

    self.backgroundImageView.isUserInteractionEnabled = true
}

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

Aucun délégué de reconnaissance de geste ni aucune autre implémentation si nécessaire.

mourodrigo
la source
2

Vous pouvez également faire glisser un outil de reconnaissance des gestes du toucher vers la vue d'image dans Storyboard. Créez ensuite une action par ctrl + dragle code.

zevij
la source
1

Pour les amoureux des blocs, vous pouvez utiliser ALActionBlocks pour ajouter une action de gestes dans un bloc

__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
la source