web-dev-qa-db-fra.com

UIGestureRecognizer sur UIImageView

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

Peut-on ajouter une UIGestureRecognizer à la UIImageView?

J'aimerais ajouter un identificateur de rotation et de pincement à une variable UIImageView qui serait créée à l'exécution.

Comment ajoute-t-on ces identifiants?

171
jarryd

Vérifiez que userInteractionEnabled est YES sur UIImageView. Ensuite, vous pouvez ajouter un identificateur de geste.

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...
}
410
user467105

Oui, un identificateur 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 propriété userInteractionEnabled sur YES. UIImageView hérite de UIView, dont la propriété d'interaction utilisateur est définie sur YES par défaut. Cependant, la propriété d'interaction utilisateur de UIImageView est définie sur NO par défaut.

À partir de 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 du fichier 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'une UIImageView avec une UIPinchGestureRecognizer, une UIRotationGestureRecognizer et une UIPanGestureRecognizer.

Tout d'abord, dans viewDidLoad, ou 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. Veillez à 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 sont détectés. À l'intérieur, nous vérifierons l'état actuel du geste et, s'il est soit dans la variable commencée ou modifiée UIGestureRecognizerState, nous lirons la propriété scale/rotation/translation du geste, appliquerons ces données à une transformation affine, appliquerons la transformation affine au image, puis réinitialisez les gestes échelle/rotation/translation. 

- (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 UIGestureRecognizerDelegate method gestureRecognizer: 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, vous pouvez simplement renvoyer YES comme indiqué ci-dessous. Toutefois, si vous avez délégué d'autres gestes pour lesquels cette classe est affectée, vous devrez peut-être ajouter une logique à cette méthode pour déterminer quel geste est lequel avant de les autoriser à 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 dans un exemple de projet, vous trouverez ici l'exemple de projet que j'ai créé et contenant ce code .

73
Mick MacCallum

Solution Swift 2.0

Vous créez un identificateur de geste de type tapotement, pincement ou balayage dans le même manoir. Ci-dessous, je vais vous guider à travers 4 étapes pour obtenir votre identificateur opérationnel.

4 étapes

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

class ViewController: UIViewController, UIGestureRecognizerDelegate {...}

2.) Faites glisser le curseur 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 vous appuierez sur votre reconnaissance de geste. (Vous pouvez exclure le = nil si vous le souhaitez).

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)
    }
}
11
Dan Beaulieu

Swift 4.2

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

et lorsque vous appuyez sur:

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

Exemple de 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é d'enregistrement de geste ni autre implémentation si nécessaire.

3
mourodrigo

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 : Faire pivoter la vue.
  3. UIPanGestureRecognizer : Faire 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 juste pour commenter. Je vous remercie

3
Leang Socheat

Vous pouvez également faire glisser un identificateur de gestes tactiles vers la vue de l'image dans Storyboard. Ensuite, créez une action par Ctrl + glisser sur le code ...

2
goggelj

Pour les amoureux des blocs, vous pouvez utiliser ALActionBlocks pour ajouter une action de gestes en 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];
0
dimo hamdy