Using UILongPressGestureRecognizer For Subviews of

2019-01-28 21:15发布

问题:

For the past four hours, I have tried many Stack Overlow solutions but none have helped solve my problem.

Here it is,

  • I have a UIScrollView
  • Within that ScrollView there is one custom UILabel and 8 custom UIImageViews
  • I want to detect a long press
  • Something like this works

    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDidFire:)];
    longPress.minimumPressDuration = 0.5; [scroll addGestureRecognizer:longPress]; //scroll defined elsewhere

However, if I replace the scroll with any subviews of scroll, the long press event never fires.

  1. How do I detect a long press of a subview of a scroll view?
  2. This is quite a messy hack, however, since I can detect long presses of a scroll view, is there any way where I can detect the position of the press so that I can see which specific subview is being pressed.

Also, (insert subview here).userInteractionEnabled = YES, I set this property for all my subviews of the scroll view, so this should not be a problem.

I have also tried using touchesBegan and touchesEnded method as suggested elsewhere in Stack Overflow.

Also, for the image views, I do set a new UILongPressGestureRecognizer for every custom image view, using a for loop, as I am aware of the 1 view per gesture recognizer rule.

From A First Time iOS Developer,

Graham

P.S. I'd really prefer if I could find a solution for 1. rather than the messy 2.


More Code As Requested:

In the Init of the view Controller

 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDidFire:)];
longPress.minimumPressDuration = 0.5;
[self.titleLabel addGestureRecognizer:longPress]; //titleLabel property initialized elsewhere
[mainView addSubview:self.titleLabel];

In a "load images" method

for (NSData * dataImg in results) {
//Does some work turning data into an image, into an image view called img
        img.delegate = self;
        img.userInteractionEnabled = YES;
        UILongPressGestureRecognizer *aLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDidFire:)];
        aLongPress.minimumPressDuration = 0.5;
        [img addGestureRecognizer:aLongPress];
        [imgContainer addSubview:img];
}

Even More Code + Notes

self.view (UIView)

->scroll (UIScrollView)

->->mainView (UIView)

->->->titleLabel (UILabel)

->->->imgContainer (UIView)

->->->->images (UIImageViews)

[self.view addSubview:scroll];
[scroll addSubview:mainView];
[mainView addSubview:self.titleLabel];
[mainView addSubview:imgContainer];
[imgContainer addSubview:img]; //done 8x via for loop

Thanks to @RegularExpression's answer, I now am aware that the mainView is getting pressed, but not its subviews, so I need to find a way to display the mainView's subviews above it. :)

Another update, titleLabel works. ImageViews still don't work though. :(

回答1:

I know this is a bit late and an answer has been chosen, but in case someone else wants a nice simple solution if you've got iOS7.

Inside your delegate of the UILongPressGestureRecognizer implement the gestureRecognizer:shouldRequireFailureOfGestureRecognizer:otherGestureRecognizer selector

Check if otherGestureRecognizer is a UIPanGestureRecognizer and return YES, otherwise return NO

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        return YES;
    }

    return NO;
}

The scroll view will actually produce a UIScrollViewPanGestureRecognizer, which is part of the private API, but it's a subclass of UIPanGestureRecognizer so the above works fine.

To support iOS6 or below, then you'll need to loop through the gestureRecognizers of the UIScrollView, detect which one is a UIPanGestureRecognizer and perform the requireGestureRecognizerToFail selector on your UILongPressGestureRecogizer with that.



回答2:

your code seems to be fine,it should work i think.i used below code and its working fine for me.

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
longPress.delegate = (id)self;
longPress.minimumPressDuration=0.05;
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer:longPress];

and its method,

- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)sender {
   NSLog(@"detected");

if (sender.state == UIGestureRecognizerStateEnded){
     UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Alert" message:@"YES"    delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
     [alert show];
   } 
}

Here i took imageView as subview of scrollview as u said



回答3:

Since your UIScrollView is the common parent, that's probably where your gesture recognizer needs to be. You can determine which subview is being pressed by looking at the location of the point supplied in your action. So, the individual subviews do not need gesture recognizers.

So, you would do something like this:

- (void)longPressDidFire:(UILongPressGestureRecognizer *)sender
{
    if (sender.state == UIGestureRecognizerStateEnded)
        CGPoint point = [sender locationInView:scroll];
        UIView *tappedView = [scroll hitTest:point withEvent:nil];

So, then you have the view that was long-pressed.

Other things that could cause the action not to fire would be a delegate problem or if the scroll is contained by another view that is intercepting the touch.

HTH



回答4:

Instead of

 [scroll addGestureRecognizer:longPress]; 

Add the gesture on your subviews, right after you declare them and before you add them to scrollview

 [subview addGestureRecognizer:longPress]; 


回答5:

Woohoo it works!

The problem was:

imgContainer was a UIView with an empty frame with several UIImageViews as subviews

I was under the impression that as I added a subview to imgContainer, imgContainer would expand.

This is not true.

I had to set imgContainer's frame to the same content frame as the scroll view and then everything became ok.

I hope this answer helps any other future iOS firs timers like me.