UIPanGestureRecognizer starting point is off

前端 未结 6 1443
庸人自扰
庸人自扰 2021-01-11 19:11

I have a UIView that has a UIPanGestureRecognizer attached to it the gesture is working fine except that the starting point is not where the pan first started it is usually

相关标签:
6条回答
  • 2021-01-11 19:34

    The documentation says that the pan gesture starts when the fingers have "moved enough to be considered a pan." This movement is to distinguish a press from a drag, since the user's finger could move around a bit while they are trying to press without dragging.

    I think this is the difference you're seeing between the first touch point and the first point considered part of the drag.

    0 讨论(0)
  • 2021-01-11 19:37

    You can detect initial touch position of a gesture with the gesture recognizer's delegate method

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
    
    0 讨论(0)
  • 2021-01-11 19:45

    The start point changing reason is as @Douglas said:

    • the pan gesture starts when the fingers have moved enough to be considered a pan.

    And the starting point and translation are both calculated after the pan gesture is recognized.

    I use the following way to get the "real" start point:

    For the view which has the pan gesture, override the -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event method, and store the "real" starting point for later use:

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        [super touchesBegan:touches withEvent:event];
        self.touchStartPoint = [[[touches allObjects] firstObject] locationInView:self];
    }
    
    0 讨论(0)
  • 2021-01-11 19:47

    Yes the difference is because the gesture recognizer waits a undetermined distance of movement before becoming active. What you can do is create your own UIPanGestureRecognizer and set the state to UIGestureRecognizerStateChanged in the touchesMoved override method.

    NOTE: I used touhcesMoved instead of touchesBegan because I wanted it to start when the users touch moved and not instantly.

    Here is some example code for a custom gesture recognizer that does this:

    #import "RAUIPanGestureRecognizer.h"
    
    @implementation RAUIPanGestureRecognizer 
    
    
    #pragma mark - UIGestureRecognizerSubclass Methods
    
    - (void)reset
        { [super reset ]; }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
        { [super touchesBegan:touches withEvent:event ]; }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
        { 
            [self setState:UIGestureRecognizerStateChanged ];
            [super touchesMoved:touches withEvent:event ]; 
        }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
        { [super touchesEnded:touches withEvent:event ]; }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
        { [super touchesCancelled:touches withEvent:event ]; }
    
    
    @end
    
    0 讨论(0)
  • 2021-01-11 19:51
      CGPoint beg = [panRecognizer locationInView:_scrollView];
      CGPoint trans = [panRecognizer translationInView:_scrollView];
      CGPoint firstTouch = CGPointSubtract(beg, trans);
    

    Put this code in the UIGestureRecognizerStateBegan case

    0 讨论(0)
  • 2021-01-11 19:51

    To get around this you could try reseting the translation point when the gesture recognizer begins. For example, start your action method out like so:

    - (void)panGesture:(UIPanGestureRecognizer *)recognizer;
    {
        if ( recognizer.state == UIGestureRecognizerStateBegan )
        {
            CGPoint point = ...; // The view's initial origin.
            UIView *superview = [recognizer.view superview];
            [recognizer setTranslation:point inView:superview];
        }
    }
    
    0 讨论(0)
提交回复
热议问题