Search code examples
iosswifttouchesmoved

Compare last position to current in TouchesMoved


Background

I want to animate a view while it's being dragged from left to right or vice versa. To determine, in which direction it's being dragged, I'm keeping track of the last x position it was in and then compare it to the current one.

Code

var lastX: CGFloat = 0
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    let currentX = (((touches.first as AnyObject) as! UITouch).view?.center ?? CGPoint.zero).x
    if lastX == 0 { lastX = currentX; return }

    if currentX > self.lastX {
        print("dragging right")
        //altering the view's size based on progress made dragging
    } else if currentX < self.lastX {
        print("dragging left")
        //altering the view's size based on progress made dragging
    }
    lastX = currentX
}

Issue

This technique works fine for dragging left, but doesn't when dragging right.

Here's what happens:

  • when dragging left, it prints several lines of "dragging left"
  • when dragging right, it prints this:
    • "dragging left"
      "dragging right"
      "dragging left"
      "dragging right"
      ...

Now, I figured that dragging left works because the code block for dragging left is being executed after the one for dragging right. Hence, when removing the second code block, dragging right works as expected.

Question

How can I better compare the last x position to the current one to make sure only the correct code block is being executed?

Note

I've realized it has something to do with the code I'm executing inside the code blocks: I alter the view's size. Apparently, it "bounces back" each time I update the size and that creates this bug.
To fix this, all I have to do is calculate using the location of the touch, rather than the view that's being dragged, since the touch's position won't be affected by altering the view's size.


Solution

  • I've realized it has something to do with the code I'm executing inside the code blocks: I alter the view's size. Apparently, it "bounces back" each time I update the size and that creates this bug.

    To fix this, all I have to do is calculate using the location of the touch, rather than the view that's being dragged, since the touch's position won't be affected by altering the view's size.

    So, I replaced this:

    let currentX = (((touches.first as AnyObject) as! UITouch).view?.center ?? CGPoint.zero).x
    

    with this:

    let currentX = ((touches.first as AnyObject) as! UITouch).location(in: self.superview).x
    

    That's it!