Add a double click to the UICollectionView; require a short tap

With a similar problem to this question , I am trying to add a double-touch gesture recognizer to an instance of a UICollectionView .

I need the default single click to UICollectionViewDelegate collectionView:didSelectItemAtIndexPath: method.

To do this, I implement the code directly from the Apple Collection View Programming Guide (Listing 4-2) :

 UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; NSArray* recognizers = [self.collectionView gestureRecognizers]; // Make the default gesture recognizer wait until the custom one fails. for (UIGestureRecognizer* aRecognizer in recognizers) { if ([aRecognizer isKindOfClass:[UITapGestureRecognizer class]]) [aRecognizer requireGestureRecognizerToFail:tapGesture]; } // Now add the gesture recognizer to the collection view. tapGesture.numberOfTapsRequired = 2; [self.collectionView addGestureRecognizer:tapGesture]; 

This code does not work as expected: tapGesture fired by double-clicking, but by default it is not used once, and the delegate method didSelect... is still called.

Passing through the debugger shows that the if condition, [aRecognizer isKindOfClass:[UITapGestureRecognizer class]] , is never evaluated as true, and therefore the failure tapGesture not set on the new tapGesture .

Running this debugger command every time through a for loop:

 po (void)NSLog(@"%@",(NSString *)NSStringFromClass([aRecognizer class])) 

shows that the default gesture recognizers are (really) not instances of UITapGestureRecognizer .

Instead, they are private classes UIScrollViewDelayedTouchesBeganGestureRecognizer and UIScrollViewPanGestureRecognizer .

Firstly, I cannot use them explicitly without violating the Private API rules. Secondly, joining UIScrollViewDelayedTouchesBeganGestureRecognizer via requireGestureRecognizerToFail: does not seem to give the desired behavior, i.e. The didSelect... delegate didSelect... is still being called.

How can I work with UICollectionView default gesture recognizers to add a double click to a collection view and prevent a single click from turning off the delegate method of collectionView:didSelectItemAtIndexPath: :?

Thanks in advance!

+6
source share
2 answers

My solution was not to implement collectionView: didSelectItemAtIndexPath, but to implement two gesture recognizers.

  self.doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processDoubleTap:)]; [_doubleTapGesture setNumberOfTapsRequired:2]; [_doubleTapGesture setNumberOfTouchesRequired:1]; [self.view addGestureRecognizer:_doubleTapGesture]; self.singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processSingleTap:)]; [_singleTapGesture setNumberOfTapsRequired:1]; [_singleTapGesture setNumberOfTouchesRequired:1]; [_singleTapGesture requireGestureRecognizerToFail:_doubleTapGesture]; [self.view addGestureRecognizer:_singleTapGesture]; 

This way I can handle single and double taps. The only thing I see is that the cell is selected in doubleTaps, but if that bothers you, you can handle it in your two selectors.

+4
source

I use the following to register a UITapGestureRecognizer:

 UITapGestureRecognizer* singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)]; singleTapGesture.delaysTouchesBegan = YES; singleTapGesture.numberOfTapsRequired = 1; // number of taps required singleTapGesture.numberOfTouchesRequired = 1; // number of finger touches required [self.collectionView addGestureRecognizer:singleTapGesture]; 

By setting delaysTouchesBegan to YES , the user-defined gesture recognizer takes precedence over listening objects in collectible viewing, delaying the registration of other touch events. In addition, you can completely cancel touch recognition by setting cancelsTouchesInView to YES .

The gesture is not processed by the following function:

 - (void)handleSingleTapGesture:(UITapGestureRecognizer *)sender { if (sender.state == UIGestureRecognizerStateEnded) { CGPoint location = [sender locationInView:self.collectionsView]; NSIndexPath *indexPath = [self.collectionsView indexPathForItemAtPoint:location]; if (indexPath) { NSLog(@"Cell view was tapped."); UICollectionViewCell *cell = [self.collectionsView cellForItemAtIndexPath:indexPath]; // Do something. } } else{ // Handle other UIGestureRecognizerState's } } 
+4
source

Source: https://habr.com/ru/post/949534/


All Articles