I've made UIPanGestureRecognizer only detect m

2020-07-29 04:12发布

问题:

I just implemented this:

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
    CGPoint translation = [panGestureRecognizer translationInView:someView];
    return fabs(translation.y) > fabs(translation.x);
}

(As outlined here.)

But if the user pans vertically just over the diagonal it will start. How do I make the tolerance much more strict for what it considers vertical?

Basically, the image below describes what I'm after. The first diagram is what it detects now, anything within that area, and the second is what I want it to do.

回答1:

You can use atan2f given x and y values to calculate the angle from vertical. For example, to start the gesture if the angle is less than 4 degrees from vertical, you can do something like this:

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gesture {
    CGPoint translation = [gesture translationInView:gesture.view];
    if (translation.x != 0 || translation.y != 0) {
        CGFloat angle = atan2f(fabs(translation.x), fabs(translation.y));
        return angle < (4.0 * M_PI / 180.0); // four degrees, but in radians
    }
    return FALSE;
}


回答2:

Detecting pure vertical gestures, I assume that translation.x == 0 then.

You should as well, check the correct answer from the post you referenced. Where he compares the previous location with the current one. You can create the sensibility. You can check my project, for example to see that, where I use this sensibility to define, when an action is valid (less or equal than the sensibility) or invalid (bigger than the sensibility). Check the MOVEMENT_SENSIBILITY inside the RPSliderViewController.m.



回答3:

I've written a UIGestureRecognizer subclass for that purpose once. It only tracks the vertical translation. Maybe that helps you. You can use it as any other gesture recognizer, just set the threshold and track the translation in the it's target's action method.

VerticalPanGestureRecognizer.h

#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>

@interface VerticalPanGestureRecognizer : UIGestureRecognizer

@property (assign, nonatomic)float translation;
@property (assign, nonatomic)float offsetThreshold;

@end

VerticalPanGestureRecognizer.m

#import "VerticalPanGestureRecognizer.h"

@interface VerticalPanGestureRecognizer ()
{
    CGPoint _startPoint;
}
@end

@implementation VerticalPanGestureRecognizer

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([touches count] > 1) {
        self.state = UIGestureRecognizerStateFailed;
    }
    else
    {
        _startPoint = [[touches anyObject] locationInView:self.view];
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (self.state == UIGestureRecognizerStateFailed || self.state == UIGestureRecognizerStateCancelled) {
        return;
    }
    CGPoint currentLocation = [[touches anyObject] locationInView:self.view];
    CGPoint translation;
    translation.x = currentLocation.x - _startPoint.x;
    translation.y = currentLocation.y - _startPoint.y;        

    if (self.state == UIGestureRecognizerStatePossible)
    {
        //if the x-translation is above our threshold the gesture fails 
        if (fabsf(translation.x) > self.offsetThreshold)
            self.state = UIGestureRecognizerStateFailed;
        //if the y-translation has reached the threshold the gesture is recognized and the we start sending action methods
        else if (fabsf(translation.y) > self.offsetThreshold)
            self.state = UIGestureRecognizerStateBegan;

        return;                
    }        
    //if we reached this point the gesture was succesfully recognized so we now enter changed state
    self.state = UIGestureRecognizerStateChanged;

    //we are just insterested in the vertical translation
    self.translation = translation.y;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    //if at this point the state is still 'possible' the threshold wasn't reached at all so we fail
    if (self.state == UIGestureRecognizerStatePossible)
    {
        self.state = UIGestureRecognizerStateFailed;
    }
    else
    {
        CGPoint currentLocation = [[touches anyObject] locationInView:self.view];
        CGPoint translation;
        translation.x = _startPoint.x - currentLocation.x;
        translation.y = _startPoint.y - currentLocation.y;
        self.translation = translation.y;
        self.state = UIGestureRecognizerStateEnded;
    }

}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.state = UIGestureRecognizerStateCancelled;
}

- (void)reset
{
    [super reset];
    _startPoint = CGPointZero;
}

@end