Search code examples
iosuiscrollviewswipe

Swipe doesn't work properly in a uiscrollview


I have an UISrollView called templateView. I must add to it a swipe gesture to allow the user to swipe left/right to see another templates. The problem is that most of times the user can't swipe easily because the view scrolls down/up instead of swiping to another view. his finger needs to be aligned strictly horizontal to swipe to another page and this isn't acceptable from a user experience perspective.

Any idea how to handle such cases? Is there a way to implement an angle for detecting the swipe gesture? or, is there a way to do it as a custom uigesture for detecting oblique lines with a specific angle?

Thanks in advance.


Solution

  • Try to implement UIGestureRecognizer Delegate method. This method is called when recognition of a gesture by either gestureRecognizer or otherGestureRecognizer would block the other gesture recognizer from recognizing its gesture. Note that returning YES is guaranteed to allow simultaneous recognition.

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
        shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer  
        {
            return YES;
        }
    

    Reference: UIGestureRecognizer Protocol

    Do not forget to assign delegate, when you are initializing your swipe gesture.

    UPDATE 1 CREATING YOUR OWN GESTURE

    You always can subclass UIGestureRecognizer class and implement touchesBegan, touchesMoved, touchesEnded methods - manually managing the states of the gesture depending on your own needs.

    I am posting some sample code of implementing custom EdgeGestureRecognizer for your better understanding.

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [super touchesBegan:touches withEvent:event];
        UITouch *touch = touches.anyObject;
        CGPoint location = [touches.anyObject locationInView:self.view];
    
        // if not single finger, then fail
    
        if ([touches count] != 1)
        {
            self.state = UIGestureRecognizerStateFailed;
            return;
        }
       //put here some logics for your case. For instance, you can register
       //here your first touch location, it will help
       //you to calculate the angle after.
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [super touchesMoved:touches withEvent:event];
    
        if (self.state == UIGestureRecognizerStateFailed) return;
    
        UITouch *touch = touches.anyObject;
        self.previousPoint = self.currentPoint;
        self.previousPointTime = self.currentPointTime;
        self.currentPoint = [touch locationInView:self.view];
        self.currentPointTime = touch.timestamp;
    
        if (self.state == UIGestureRecognizerStatePossible)
        {
            CGPoint translate = CGPointMake(self.currentPoint.x - self.startPoint.x, self.currentPoint.y - self.startPoint.y);
    
            // see if we've moved the necessary minimum distance
    
            if (sqrt(translate.x * translate.x + translate.y * translate.y) >= self.minimumRecognitionDistance)
            {
                // recognize if the angle is roughly horizontal, otherwise fail
    
                double angle = atan2(translate.y, translate.x);
    
                if ([self isAngleCloseEnough:angle])
                    self.state = UIGestureRecognizerStateBegan;
                else
                    self.state = UIGestureRecognizerStateFailed;
            }
        }
        else if (self.state == UIGestureRecognizerStateBegan)
        {
            self.state = UIGestureRecognizerStateChanged;
        }
    }