UIPanGestureRecognizer do something immediately when touched

戏子无情 提交于 2019-11-30 11:44:22

I needed to do this too, and Jake's suggestion worked perfectly for me. In case it helps anyone who comes across this in the future, here is my subclass implementation of UIPanGestureRecognizer (the header remains unchanged):

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

@implementation ImmediatePanGestureRecognizer

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    self.state = UIGestureRecognizerStateBegan;
}

@end

This is all you need—this will fire as soon as you put your finger down on the view, update as soon as you move your finger a single point in any direction, and provide the functionality of a regular UIPanGestureRecognizer (like translationInView and velocityInView) before a regular one would've fired, all without breaking any existing functionality.

I have implemented George WS's answer. With a little testing I realized that additional touch events that occur after the initial touch, but before the initial touch ends are not being properly handled. Here is my updated implementation. It's a bit naive, but prevents bizarre behavior caused by the UIGestureRecognizerStateBegan happening multiple times.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.state >= UIGestureRecognizerStateBegan) {
        return;
    }

    [super touchesBegan:touches withEvent:event];
    self.state = UIGestureRecognizerStateBegan;
}

Swift 3/4 Solution

import UIKit.UIGestureRecognizerSubclass

class InstantPanGestureRecognizer: UIPanGestureRecognizer {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        if (self.state == UIGestureRecognizerState.began) { return }
        super.touchesBegan(touches, with: event)
        self.state = UIGestureRecognizerState.began
    }

}

According to the documentation UIPanGestureRecognizer only enters UIGestureRecognizerStateBegan when "the minimum number of fingers allowed (minimumNumberOfTouches) has moved enough to be considered a pan". If you want something to happen as soon as you touch, you could try subclassing UIPanGestureRecognizer and over riding touchesBegan:withEvent:.

Thanks George WS & Derrick Hathaway

Swift 2.2

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) {
  if (self.state == UIGestureRecognizerState.Began) {
    return
  }
  super.touchesBegan(touches, withEvent: event)
  self.state = UIGestureRecognizerState.Began;
}

And you must add to your Bridging-Header:

#import <UIKit/UIGestureRecognizerSubclass.h>

I draw in a view that is part of a UIScrollView. I use a UIPanGestureRecognizer to draw in the view. This UIPanGestureRecognizer has minimumNumberOfTouches and maximumNumberOfTouches set to 1.

I use the UIPinchGestureRecognizer and the UIPanGestureRecognizer from the scrollView for panning and zooming. The UIPanGestureRecognizer of the scrollView has minimumNumberOfTouches and maximumNumberOfTouches set to 2.

I used the solution of George WS and I noticed that the drawing started quick, but it was difficult to recognize the pinch gesture for zooming and the two-finger pan gesture for panning. I changed the solution slightly and I use touchesMoved to recognize the start of the drawing. Zooming and panning was better recognized.

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
    super.touchesMoved(touches, with: event)
    state = UIGestureRecognizer.State.began
}

I'm trying to do a similar thing, and the resolution I've been working on is to use the view's touchesBegan:withEvent: to perform the actions I want to happen the instant the user touches the screen. Then the gesture handler takes over once the touch becomes a gesture.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!