Maystro
Maystro

Reputation: 2955

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.

Upvotes: 1

Views: 1308

Answers (2)

Ahmed Zaidan
Ahmed Zaidan

Reputation: 68

This works for me even over a scroll view in swift UI, I was having the same problem where edge swipes didn't work over the scroll view:

extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }

    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

Upvotes: 0

Neil Galiaskarov
Neil Galiaskarov

Reputation: 5073

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;
    }
}

Upvotes: 4

Related Questions