How to pass a hard gesture to a UICollectionVIew from a UICollectionViewCell?

I have a UICollectionView grid implementation based on a UICollectionViewCells table. To allow cells to respond to drag and drop, I separately add a UIPanGestureRecognizer to each cell.

UICollectionView still scrolls (horizontally) when I touch and scroll left / right, starting from the points between the cells, but as long as the pan gestures recognizer is added to the cell, CollectionView seems to refuse to scroll when I start using swipe in the cell.

Right now, I am separating horizontal left / right drag from vertical drag up / down, so there should be no conflict between dragging cells (vertical scroll) and CollectionView scroll (horizontal scroll). In this case, how can I pass the swipe to the collection / scroll view so that it can scroll as usual? It is really annoying to start with the border or distance between cells.

As soon as I remove the pan gestures from the cell, scrolling works fine, regardless of whether I start to start the cell or between cells.

EDIT: The desired behavior of gestures in the form is carried below as the current code

 // Handle pans by detecting swipes: -(void) handlePan:(UIPanGestureRecognizer*)recognizer { // Calculate touch location CGPoint touchXY = [recognizer locationInView:masterWindowView]; // Handle touch if (recognizer.state == UIGestureRecognizerStateBegan) { gestureWasHandled = NO; pointCount = 1; startPoint = touchXY; } if (recognizer.state == UIGestureRecognizerStateChanged) { ++pointCount; // Calculate whether a swipe has occurred float dX = deltaX(touchXY, startPoint); float dY = deltaY(touchXY, startPoint); BOOL finished = YES; if ((dX > kSwipeDragMin) && (ABS(dY) < kDragLimitMax)) { touchType = TouchSwipeLeft; NSLog(@"LEFT swipe detected"); [recognizer requireGestureRecognizerToFail:recognizer]; //[masterScrollView handlePan] } else if ((dX < -kSwipeDragMin) && (ABS(dY) < kDragLimitMax)) { touchType = TouchSwipeRight; NSLog(@"RIGHT swipe detected"); [recognizer requireGestureRecognizerToFail:recognizer]; } else if ((dY > kSwipeDragMin) && (ABS(dX) < kDragLimitMax)) { touchType = TouchSwipeUp; NSLog(@"UP swipe detected"); } else if ((dY < -kSwipeDragMin) && (ABS(dX) < kDragLimitMax)) { touchType = TouchSwipeDown; NSLog(@"DOWN swipe detected"); } else finished = NO; // If unhandled and downward, produce a new draggable view if (!gestureWasHandled && finished && (touchType == TouchSwipeDown)) { [self.delegate cellBeingDragged:self]; dragView.center = touchXY; dragView.hidden = NO; dragView.backgroundColor = [UIColor clearColor]; masterScrollView.scrollEnabled = NO; // prevent user from scrolling during gestureWasHandled = YES; } else if (gestureWasHandled) { // allow continued dragging after detection dragView.center = touchXY; } } if (recognizer.state == UIGestureRecognizerStateEnded) { // ensure that scroll view returns to scrollable if (gestureWasHandled) { [self.delegate cell:self dragEndedAt:touchXY]; } } } // Allow simultaneous recognition -(BOOL) gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { return YES; } 

This code works when it is provided to each individual cell. It does NOT work when it is connected to the UICollectionView as a gesture recognizer, and it actually stops scrolling.

+7
ios objective-c foundation
source share
2 answers

Instead of binding a UIPanGestureRecognizer to each cell (which will lead to poor performance), add a UIPanGestureRecognizer to the UICollectionView , and when using pan gestures, use locationInView to get the point to the UICollectionView where the panorama started, and then indexPathForItemAtPoint , which will return you the index path for cell you have to revive.

Thus, you will have only one gesture recognizer (good!) For your entire viewing of the collection, as well as support for the control in your viewing controller (as you wanted) - a double victory!

Using this solution, in your view controller, you would execute gestureRecognizer: shouldReceiveTouch:, take this registry Recognizer, make sure its UIPanGestureRecognizer and use the translationInView: method to find out if the translation is on the X or Y axis. Use this information to decide Do you want to return YES or NO. For example:

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if([gestureRecognizer isEqual:myTapGesture]) { CGPoint point = [gestureRecognizer translationInView:self.collectionView]; if(point.x != 0) { //adjust this condition if you want some leniency on the X axis //The translation was on the X axis, ie right/left, //so this gesture recognizer shouldn't do anything about it return NO; } } return YES; } 
+9
source share

Having -shouldReceiveTouch: and -shouldRecognizeSimultaneousWithGestureRecognizer: returning YES, adding UIGestureRecognizerDelegate to the list of protocols for your class, and delegating your gesture delegate to -viewDidLoad.

 yourGesture.delegate = self; 
+5
source share

All Articles