87650

Attach GestureRecogniser to multiple imageviews

Something strange I encountered today while attaching same gesture recogniser to multiple image views. It gets attached to only the last one, in other words, it can be attached to only one view!

I had to create multiple gesture recognisers to meet my requirements.

Following is what I have done. Am I doing correct? Is that's the only way to attach recognisers to the multiple imageviews?

Please note that I don't want to use UITableView or UIVIew and put all imageviews in it and attach gesture recogniser to only UITableView or UIVIew. I have all image scattered and I have to detect which image is being dragged. Thanks.

[imgView1 setUserInteractionEnabled:YES]; [imgView1 setMultipleTouchEnabled:YES]; [imgView2 setUserInteractionEnabled:YES]; [imgView2 setMultipleTouchEnabled:YES]; [imgView3 setUserInteractionEnabled:YES]; [imgView3 setMultipleTouchEnabled:YES]; [imgView4 setUserInteractionEnabled:YES]; [imgView4 setMultipleTouchEnabled:YES]; [imgView5 setUserInteractionEnabled:YES]; [imgView5 setMultipleTouchEnabled:YES]; [imgView6 setUserInteractionEnabled:YES]; [imgView6 setMultipleTouchEnabled:YES]; //Attach gesture recognizer to each imagviews gestureRecognizer1 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; gestureRecognizer1.delegate = self; gestureRecognizer2 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; gestureRecognizer2.delegate = self; gestureRecognizer3 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; gestureRecognizer3.delegate = self; gestureRecognizer4 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; gestureRecognizer4.delegate = self; gestureRecognizer5 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; gestureRecognizer5.delegate = self; gestureRecognizer6 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; gestureRecognizer6.delegate = self; [imgView1 addGestureRecognizer:gestureRecognizer1]; [imgView2 addGestureRecognizer:gestureRecognizer2]; [imgView3 addGestureRecognizer:gestureRecognizer3]; [imgView4 addGestureRecognizer:gestureRecognizer4]; [imgView5 addGestureRecognizer:gestureRecognizer5]; [imgView6 addGestureRecognizer:gestureRecognizer6];

Answer1:

Yes, one view per gesture recognizer. So if you want only one recognizer, put it on the superview, e.g.:

UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gestureHandler:)]; [self.view addGestureRecognizer:gestureRecognizer];

And then, in your handler, you can:

- (void)handleLongPress:(UILongPressGestureRecognizer *)sender { CGPoint location = [sender locationInView:self.view]; if (sender.state == UIGestureRecognizerStateBegan) { for (UIView *view in self.view.subviews) { if ([view isKindOfClass:[UIImageView class]] && CGRectContainsPoint(view.frame, location)) { UIImageView *image = (UIImageView *) view; // ok, now you know which image you received your long press for // do whatever you wanted on it at this point return; } } } }

By the way, if you do that, you don't need to worry about enabling user interaction on the images, either.

Finally, you don't need to worry about specifying your gesture recognizer's delegate unless you're going to conform to UIGestureRecognizerDelegate, which this isn't. Also note that I'm using a local var for my recognizer because there's no reason to hang onto it.

<strong>Update:</strong>

While the above code works fine, perhaps even better would be a custom long press gesture recognizer that would fail if the long press didn't take place over an image (this way it's more likely to play well in case you have other gesture recognizers taking place in your view). So:

#import <UIKit/UIGestureRecognizerSubclass.h> @interface ImageLongPressGestureRecognizer : UILongPressGestureRecognizer @property (nonatomic, weak) UIImageView *imageview; @end @implementation ImageLongPressGestureRecognizer @synthesize imageview = _imageview; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { self.imageview = nil; [super touchesBegan:touches withEvent:event]; CGPoint location = [self locationInView:self.view]; for (UIView *view in self.view.subviews) { if ([view isKindOfClass:[UIImageView class]] && CGRectContainsPoint(view.frame, location)) { self.imageview = (UIImageView *)view; return; } } self.state = UIGestureRecognizerStateFailed; } @end

then create your gesture recognizer accordingly, using this new subclass:

ImageLongPressGestureRecognizer *gestureRecognizer = [[ImageLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; [self.view addGestureRecognizer:gestureRecognizer];

and then, as a nice little benefit of this subclassing, your main gesture recognizer is simplified, namely:

- (void)handleLongPress:(ImageLongPressGestureRecognizer *)sender { if (sender.state == UIGestureRecognizerStateBegan) { // you can now do whatever you want with sender.imageview, e.g. this makes it blink for you: [UIView animateWithDuration:0.5 animations:^{ sender.imageview.alpha = 0.0; } completion:^(BOOL finished){ [UIView animateWithDuration:0.5 animations:^{ sender.imageview.alpha = 1.0; } completion:nil]; }]; } }

Answer2:

You can't attach a gesture recognizer to more than one object (as you discovered). One solution to what you are doing might be to subclass UIImageView and have setup code in that class so each view creates its recognizer, etc.

Answer3:

I guess, first of all, you should make an array of views and array of recognizers (mutable array, if needed) and then populate it. It will help you to use cycles to avoid code duplication.

As for multiple view with one recognizer - no, it's not possible, answered here.

Recommend

  • How to set Horizontal text field in landscape mode with auto layout?
  • UIImageView loses quality after panning?
  • Autolayout labels with UIView and Labels inside UIView
  • Could not find member indexPathForCell
  • Button in custom cell in dynamic table: how to know which row in action method? [duplicate]
  • When two labels show side by side with using the Masonry, how to make the width of each label show d
  • put subviews of a UIView in front of its CALayer?
  • How to shrink UILabel spacing between lines without label being clipped?
  • How to align Custom cells to Right Detail and Basic cells?
  • Adding custom UIViews to a UIScrollview - how to calculate position, size and handle zoom?
  • Manage slider during Playing Audio in tableview while scrolling
  • How to remove the outer border of UITextField presented in UIAlertActionController
  • How does iOS determine to apply the autoresizing masks if launched on iPad?
  • How can I dismiss view?
  • How to scroll UITextView above Keyboard in a UITableView in swift
  • memory bad access?
  • ABPersonViewController delete button warnning
  • Detect when UITableViewCell goes out of scope
  • How to make image rotation and 3D transform simultaneously?
  • Change size of UIViewTable to accommodate for AdWhirl Ad
  • How to detect or define the the orientation of a pinch gesture with UIPinchGestureRecognizer?
  • Programmatically change height of navigation bar in swift
  • UILabel Over UISlider Thumb
  • NSLayoutConsstraint constant not affecting view after UITapGestureRecognizer was tapped
  • gestureRecognizer shouldReceiveTouch persisting in deallocated view causing crash
  • tableView is hiding due to a gestureRecognizer before it can execute didSelectRowAtIndexPath
  • Recognizing multiple UILabels tap for UITapGestureRecogniser
  • How to set UIView size to match parrent without constraints programmatically
  • Call function in view controller from UITableViewCell
  • gestureRecognizer shouldReceiveTouch persisting in deallocated view causing crash
  • tableView is hiding due to a gestureRecognizer before it can execute didSelectRowAtIndexPath
  • Constraint to add more space between two UIViews
  • Constraints and margins in xcode 6, margins revealing whitespace after snap
  • Attach GestureRecogniser to multiple imageviews
  • UIScrollView layoutSubviews behavior changes in iOS 5?
  • How can I add a gradient that spans two views?
  • how can i do UIView animateWithDuration in viewDidLoad? ios7
  • access an alertView's calling view
  • UILongPressGestureRecognizer not working
  • How to make the tableview response pan gesture in ZUUIRevealController