Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cell stops responding to selection after pan

The Problem:

After I finish a pan gesture, the cell under the initiating tap no longer responds to selection. didSelectItemAtIndexPath will fire when tapping other cells, but not the cell that was under the pan gesture.

How can I get that cell to respond to touch input again? Alternatively, how can I check if that cell is stuck responding to an event?

Background:

  • I have a UICollectionView with a bunch of cells. Tapping a cell in this collection view fires didSelectItemAtIndexPath.
  • The collection view has a pan gesture recognizer. Panning creates an image of the view and translates it around the screen. The collection view is left underneath the other views for the duration of the pan gesture.

Theories:

It's possible that the selection is never completing due to the pan. Maybe there's a touch event hanging around in the UI. If I could clear it, maybe the cell would respond again. I tried setting [panHandler setCancelsTouchesInView:YES], but it didn't change anything.

Update 1:

In the comments, a couple people suggested that the image may be hanging around and blocking the touch. In the completion block passed to animateWithDuration, I have the following lines:

[self.regionScreenshot removeFromSuperview];
self.regionScreenshot = nil;

I verified that these lines are executed.

Another factor that leads me to believe that that is not the issue is that, of all the cells, only ones that have been used to drag are affected. Surrounding cells still respond.

Update 2: Code & Gif

- (IBAction)handlePanFrom:(UIPanGestureRecognizer*)recognizer
{
    CGPoint translation = [recognizer translationInView:recognizer.view];
    float transparencyLevel = 0.85;

    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        SFCYRegion* centerRegion = self.region;

        //North
        if (centerRegion.regionToNorth != nil)
        {
            self.region = centerRegion.regionToNorth;
            [self reloadRegion];
            self.regionToNorthScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToNorthScreenshot = [[UIView alloc] init];
            self.regionToNorthScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToNorthScreenshot];
        self.regionToNorthScreenshot.alpha = transparencyLevel;
        self.regionToNorthScreenshot.frame = northFrame;

        //East
        if (centerRegion.regionToEast != nil)
        {
            self.region = centerRegion.regionToEast;
            [self reloadRegion];
            self.regionToEastScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToEastScreenshot = [[UIView alloc] init];
            self.regionToEastScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToEastScreenshot];
        self.regionToEastScreenshot.alpha = transparencyLevel;
        self.regionToEastScreenshot.frame = eastFrame;

        //South
        if (centerRegion.regionToSouth != nil)
        {
            self.region = centerRegion.regionToSouth;
            [self reloadRegion];
            self.regionToSouthScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToSouthScreenshot = [[UIView alloc] init];
            self.regionToSouthScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToSouthScreenshot];
        self.regionToSouthScreenshot.alpha = transparencyLevel;
        self.regionToSouthScreenshot.frame = southFrame;

        //West
        if (centerRegion.regionToWest != nil)
        {
            self.region = centerRegion.regionToWest;
            [self reloadRegion];
            self.regionToWestScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToWestScreenshot = [[UIView alloc] init];
            self.regionToWestScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToWestScreenshot];
        self.regionToWestScreenshot.alpha = transparencyLevel;
        self.regionToWestScreenshot.frame = westFrame;

        //Northeast
        if (centerRegion.regionToNorth != nil && centerRegion.regionToNorth.regionToEast != nil)
        {
            self.region = centerRegion.regionToNorth.regionToEast;
            [self reloadRegion];
            self.regionToNortheastScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToNortheastScreenshot = [[UIView alloc] init];
            self.regionToNortheastScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToNortheastScreenshot];
        self.regionToNortheastScreenshot.alpha = transparencyLevel;
        self.regionToNortheastScreenshot.frame = northeastFrame;

        //Southeast
        if (centerRegion.regionToSouth != nil && centerRegion.regionToSouth.regionToEast != nil)
        {
            self.region = centerRegion.regionToSouth.regionToEast;
            [self reloadRegion];
            self.regionToSoutheastScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToSoutheastScreenshot = [[UIView alloc] init];
            self.regionToSoutheastScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToSoutheastScreenshot];
        self.regionToSoutheastScreenshot.alpha = transparencyLevel;
        self.regionToSoutheastScreenshot.frame = southeastFrame;

        //Southwest
        if (centerRegion.regionToSouth != nil && centerRegion.regionToSouth.regionToWest != nil)
        {
            self.region = centerRegion.regionToSouth.regionToWest;
            [self reloadRegion];
            self.regionToSouthwestScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToSouthwestScreenshot = [[UIView alloc] init];
            self.regionToSouthwestScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToSouthwestScreenshot];
        self.regionToSouthwestScreenshot.alpha = transparencyLevel;
        self.regionToSouthwestScreenshot.frame = southwestFrame;

        //Northwest
        if (centerRegion.regionToNorth != nil && centerRegion.regionToNorth.regionToWest != nil)
        {
            self.region = centerRegion.regionToNorth.regionToWest;
            [self reloadRegion];
            self.regionToNorthwestScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        }
        else
        {
            self.regionToNorthwestScreenshot = [[UIView alloc] init];
            self.regionToNorthwestScreenshot.backgroundColor = [UIColor darkGrayColor];
        }
        [self.view.superview addSubview:self.regionToNorthwestScreenshot];
        self.regionToNorthwestScreenshot.alpha = transparencyLevel;
        self.regionToNorthwestScreenshot.frame = northwestFrame;



        //Self
        self.region = centerRegion;
        [self reloadRegion];
        self.regionScreenshot = [self.collectionView snapshotViewAfterScreenUpdates:YES];
        self.regionScreenshot.frame = mainFrame;
        self.regionScreenshot.center = mainFrameCenter;
        [self.view.superview addSubview:self.regionScreenshot];

        self.collectionView.alpha = 0;
    }
    else if (recognizer.state == UIGestureRecognizerStateChanged)
    {
        //Track the movement:
        self.regionScreenshot.center = [self movePoint:mainFrameCenter
                                                   byX:translation.x andY:translation.y];
        self.regionToNorthScreenshot.center = [self movePoint:northFrameCenter
                                                          byX:translation.x andY:translation.y];
        self.regionToEastScreenshot.center = [self movePoint:eastFrameCenter
                                                         byX:translation.x andY:translation.y];
        self.regionToSouthScreenshot.center = [self movePoint:southFrameCenter
                                                          byX:translation.x andY:translation.y];
        self.regionToWestScreenshot.center = [self movePoint:westFrameCenter byX:translation.x andY:translation.y];
        self.regionToNortheastScreenshot.center = [self movePoint:northeastFrameCenter
                                                              byX:translation.x andY:translation.y];
        self.regionToSoutheastScreenshot.center = [self movePoint:southeastFrameCenter
                                                              byX:translation.x andY:translation.y];
        self.regionToSouthwestScreenshot.center = [self movePoint:southwestFrameCenter
                                                              byX:translation.x andY:translation.y];
        self.regionToNorthwestScreenshot.center = [self movePoint:northwestFrameCenter
                                                              byX:translation.x andY:translation.y];

        //[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded)
    {
        SFCYRegion* newRegion;
        UIView* viewToMoveToCenter;
        CGSize slideVector;
        NSInteger movedByX = 0;
        NSInteger movedByY = 0;

        float thresholdPercentage = 0.4;
        BOOL isOverThresholdToNorth = translation.y > (mainFrame.size.height * thresholdPercentage);
        BOOL isOverThresholdToSouth = -translation.y > (mainFrame.size.height * thresholdPercentage);
        BOOL isOverThresholdToEast = -translation.x > (mainFrame.size.width * thresholdPercentage);
        BOOL isOverThresholdToWest = translation.x > (mainFrame.size.width * thresholdPercentage);

        if (isOverThresholdToNorth && self.region.regionToNorth != nil)
        {
            movedByY = -1;

            if (isOverThresholdToEast && self.region.regionToNorth.regionToEast != nil)
            {
                //Northeast
                newRegion = self.region.regionToNorth.regionToEast;
                viewToMoveToCenter = self.regionToNortheastScreenshot;
                movedByX = 1;
            }
            else if (isOverThresholdToWest && self.region.regionToNorth.regionToWest != nil)
            {
                //Northwest
                newRegion = self.region.regionToNorth.regionToWest;
                viewToMoveToCenter = self.regionToNorthwestScreenshot;
                movedByX = -1;
            }
            else
            {
                //North
                newRegion = self.region.regionToNorth;
                viewToMoveToCenter = self.regionToNorthScreenshot;
            }
        }
        else if (isOverThresholdToSouth && self.region.regionToSouth != nil)
        {
            movedByY = 1;

            if (isOverThresholdToEast && self.region.regionToSouth.regionToEast != nil)
            {
                //Southeast
                newRegion = self.region.regionToSouth.regionToEast;
                viewToMoveToCenter = self.regionToSoutheastScreenshot;
                movedByX = 1;
            }
            else if (isOverThresholdToWest && self.region.regionToSouth.regionToWest != nil)
            {
                //Southwest
                newRegion = self.region.regionToSouth.regionToWest;
                viewToMoveToCenter = self.regionToSouthwestScreenshot;
                movedByX = -1;
            }
            else
            {
                //South
                newRegion = self.region.regionToSouth;
                viewToMoveToCenter = self.regionToSouthScreenshot;
            }
        }
        else if (isOverThresholdToEast && self.region.regionToEast != nil)
        {
            //East
            newRegion = self.region.regionToEast;
            viewToMoveToCenter = self.regionToEastScreenshot;
            movedByX = 1;
        }
        else if (isOverThresholdToWest && self.region.regionToWest != nil)
        {
            //West
            newRegion = self.region.regionToWest;
            viewToMoveToCenter = self.regionToWestScreenshot;
            movedByX = -1;
        }
        else
        {
            //None, so return to start:
            newRegion = self.region;
            viewToMoveToCenter = self.regionScreenshot;
        }

        slideVector = CGSizeMake(mainFrameCenter.x - viewToMoveToCenter.center.x,
                                 mainFrameCenter.y - viewToMoveToCenter.center.y);

        [UIView animateWithDuration:0.2
                         animations:^
         {
             viewToMoveToCenter.alpha = 1;
             if (![self.regionScreenshot isEqual:viewToMoveToCenter])
             {
                 self.regionScreenshot.alpha = transparencyLevel;
             }
             self.regionScreenshot.center = [self movePoint:self.regionScreenshot.center
                                                        byX:slideVector.width andY:slideVector.height];
             self.regionToNorthScreenshot.center =  [self movePoint:self.regionToNorthScreenshot.center
                                                                byX:slideVector.width andY:slideVector.height];
             self.regionToEastScreenshot.center =  [self movePoint:self.regionToEastScreenshot.center
                                                               byX:slideVector.width andY:slideVector.height];
             self.regionToSouthScreenshot.center =  [self movePoint:self.regionToSouthScreenshot.center
                                                                byX:slideVector.width andY:slideVector.height];
             self.regionToWestScreenshot.center =  [self movePoint:self.regionToWestScreenshot.center
                                                               byX:slideVector.width andY:slideVector.height];
             self.regionToNortheastScreenshot.center = [self movePoint:self.regionToNortheastScreenshot.center
                                                                   byX:slideVector.width andY:slideVector.height];
             self.regionToSoutheastScreenshot.center = [self movePoint:self.regionToSoutheastScreenshot.center
                                                                   byX:slideVector.width andY:slideVector.height];
             self.regionToSouthwestScreenshot.center = [self movePoint:self.regionToSouthwestScreenshot.center
                                                                   byX:slideVector.width andY:slideVector.height];
             self.regionToNorthwestScreenshot.center = [self movePoint:self.regionToNorthwestScreenshot.center
                                                                   byX:slideVector.width andY:slideVector.height];
         }
                         completion:^(BOOL finished)
         {
             if (finished)
             {
                 //Remove the old views:
                 self.collectionView.alpha = 1;
                 [self.regionScreenshot removeFromSuperview];
                 [self.regionToNorthScreenshot removeFromSuperview];
                 [self.regionToEastScreenshot removeFromSuperview];
                 [self.regionToSouthScreenshot removeFromSuperview];
                 [self.regionToWestScreenshot removeFromSuperview];
                 [self.regionToNortheastScreenshot removeFromSuperview];
                 [self.regionToSoutheastScreenshot removeFromSuperview];
                 [self.regionToSouthwestScreenshot removeFromSuperview];
                 [self.regionToNorthwestScreenshot removeFromSuperview];
                 self.regionScreenshot = nil;
                 self.regionToNorthScreenshot = nil;
                 self.regionToEastScreenshot = nil;
                 self.regionToSouthScreenshot = nil;
                 self.regionToWestScreenshot = nil;
                 self.regionToNortheastScreenshot = nil;
                 self.regionToSoutheastScreenshot = nil;
                 self.regionToSouthwestScreenshot = nil;
                 self.regionToNorthwestScreenshot = nil;
             }
         }];

        if (![self.regionScreenshot isEqual:viewToMoveToCenter])
        {
            self.region = newRegion;
            [self reloadRegion];
            [self movedRegionByX:movedByX andY:movedByY];
        }

        [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
    }
}

Here is an image demonstrating the issue. I perform a selection on the "Suburb" cell, then pan, and then am no longer able to perform a selection on that cell, but can still select others: Animation of bug

Update 3: All Gestures

This occurs when I do swipe gestures and pinch gestures as well. If I add in two-finger swipe gestures, both cells under the origin points are affected.

like image 778
user664939 Avatar asked Nov 02 '22 01:11

user664939


1 Answers

Make sure that regionScreenshot and any other view's you add to the view hierarchy have userInteractionEnabled set to NO.

Also set your cell and its content's clipsToBounds set to YES. Sometimes views look OK but actually they are "much smaller than they appear".

like image 95
Rivera Avatar answered Nov 12 '22 11:11

Rivera