0
votes

I'm trying to use a gesture recognizer to allow the user to resize a view on the screen by dragging it with one finger... as such, I want to track all changes to the touch. I initially tried to use a PanGestureRecognizer for this, but I've run into an issue when the user touches the view with multiple fingers. I only want to track the first touch (ie the first finger the user places on the screen during a gesture), but I can't find a way to prevent additional touches from interfering with my ability to track the first. My initial solution was to simply set

recognizer.maximumNumberOfTouches = 1

However, this causes the entire gesture to be cancelled in the event of a second touch (I want to continue tracking the first touch in this case). But, of course, not setting this value to 1 causes the gesture to actually track multiple touches. How can I make a gesture recognizer that tracks all changes to only the first touch in the gesture, and isn't cancelled by additional touches on the screen?

2
What happen if you remove recognizer.maximumNumberOfTouches = 1 this line?TheTiger
With a standard PanGestureRecognizer, it tracks both touches. With my custom recognizer, it cancels the entire gesture (but seems to be slightly delayed in doing so).kmell96
Just get rid of that touchesMoved implementation.matt
@matt But after began if user touches his second finger in that case touchBegan will not call again.. isn't it?TheTiger
Right but you don’t want it to. You want to just keep tracking the first finger, and that’s just what will happenmatt

2 Answers

-1
votes

From your comments and answer, it sounds like your use of a pan gesture recognizer was always wrong and you were doing something wrong in your action handler. No correct action handler for a pan gesture recognizer would ever use location(in:) for anything. location(in:) gives you a centroid of all touches, which is exactly what you say you don't want — and in any case there is no need to consult it.

  • If your goal is to drag a view, you use translation(in:).

  • If your goal is to track the actual location of a particular touch, you use location(ofTouch:in:).

  • If you discover that a touch is being delivered and you don't want it tracked, call ignore(_:for:).

-1
votes

Here is a UIGestureRecognizer subclass that will track all changes the first touch the user places on the screen at the start of a gesture, and will ignore all other fingers without cancelling the gesture. Note that if you're using functions/properties of the gesture recognizer (such as location(in:)), you'll probably have to override those as well.

class FirstTouchGestureRecognizer: UIGestureRecognizer {
    private var firstTouch: UITouch? = nil

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        if firstTouch == nil {
            firstTouch = touches.first!
            self.state = .began
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        if firstTouch != nil && touches.contains(firstTouch!) {
            self.state = .changed
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        if firstTouch != nil && touches.contains(firstTouch!) {
            firstTouch = nil
            self.state = .ended
        }
    }
}