43

I'm moving my views by

UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveRight:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[bubbleView[rightCnt] addGestureRecognizer:panRecognizer];
[panRecognizer release];

Now , I want to do same thing by drag with long press.

Any idea?

Dilip Manek
  • 9,095
  • 5
  • 44
  • 56
PJR
  • 13,052
  • 13
  • 64
  • 104

5 Answers5

91

UILongPressGestureRecognizer already does what you want for you. Take a look at the UIGestureRecognizerState property. From the documentation:

Long-press gestures are continuous. The gesture begins (UIGestureRecognizerStateBegan) when the number of allowable fingers (numberOfTouchesRequired) have been pressed for the specified period (minimumPressDuration) and the touches do not move beyond the allowable range of movement (allowableMovement). The gesture recognizer transitions to the Change state whenever a finger moves, and it ends (UIGestureRecognizerStateEnded) when any of the fingers are lifted.

So essentially after your UILongPressGestureRecognizerselector is called you listen to UIGestureRecognizerStateBegan, UIGestureRecognizerStateChanged, UIGestureRecognizerStateEnded. Keep changing your views frame during UIGestureRecognizerStateChanged.

- (void)moveRight:(UILongPressGestureRecognizer *)gesture
{
    if(gesture.state == UIGestureRecognizerStateBegan)
    {
        //if needed do some initial setup or init of views here
    }
    else if(gesture.state == UIGestureRecognizerStateChanged)
    {
        //move your views here.
        [yourView setFrame:];
    }
    else if(gesture.state == UIGestureRecognizerStateEnded)
    {
        //else do cleanup
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Srikar Appalaraju
  • 71,928
  • 54
  • 216
  • 264
  • 3
    i am using CGPoint translatedPoint = [(UILongPressGestureRecognizer*)sender translationInView:self.view]; but tor long press what i have to use ? – PJR Feb 14 '12 at 06:23
  • try `[yourView setFrame:CGRectMake(xCoord,yCoord,height,width)]` – Srikar Appalaraju Feb 14 '12 at 06:26
  • 4
    but by this how can i get translatedPoint – PJR Feb 14 '12 at 06:30
  • why do you need `translatedPoint`? You want to longtap on a view & drag it around right? in `UIGestureRecognizerStateEnded` you write code to get the new location for that view. – Srikar Appalaraju Feb 14 '12 at 06:48
  • 5
    @SrikarAppal you do not answer totally to the question. PJR wanted to know how to get the finger coordinates each time `UIGestureRecognizerStateChanged` was called. And the answer was: by using `[myGestureRecognizer locationInView:aView]` – Martin Jun 17 '16 at 16:55
  • Thanks so much, I would like to point out that this is the best solution for checking a long press gesture and a drag into a certain UIView. Saves the hassle of figuring out touchesmoved etc.. Thanks! – Munib Dec 24 '16 at 20:24
37
@implementation MyViewController {
    CGPoint _priorPoint;
}

- (void)moveRight:(UILongPressGestureRecognizer *)sender {
    UIView *view = sender.view;
    CGPoint point = [sender locationInView:view.superview];
    if (sender.state == UIGestureRecognizerStateChanged) {
        CGPoint center = view.center;
        center.x += point.x - _priorPoint.x;
        center.y += point.y - _priorPoint.y;
        view.center = center;
    }
    _priorPoint = point;
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • what do you set priorPoint to initially? – RanLearns Apr 22 '18 at 17:57
  • You don't need to set it to anything in particular, because `sender.state` will always be `Began` before it is `Changed`. This means `_priorPoint` will always be initialized before it is used. – rob mayoff Apr 22 '18 at 18:06
  • But priorPoint starts off initially as (0.0, 0.0) so with this code the initial touch would move the center of the object by more than the difference of the point's location and the center's location. I had to set priorPoint to the view's center in the `Began` state – RanLearns Apr 22 '18 at 18:34
  • For future readers - I was hoping to combine the dragging movement of UIPanGestureRecognizer with the ability to take action on the initial tap using UITapGestureRecognizer. I played around with the answers here for UILongPressGestureRecognizer but while this seems to have worked for others, the calculation of the object's position as it is moved didn't reach the quality of using UIPanGestureRecognizer - which is what I ended up returning to using. For me [this answer](https://stackoverflow.com/a/30033003/428981) was helpful in providing a solution to recognize simultaneous gesture recognizers – RanLearns Apr 22 '18 at 19:35
5

In Swift this can be achieved using below code

class DragView: UIView { 
  // Starting center position
  var initialCenter: CGPoint?

  override func didMoveToWindow() {
    super.didMoveToWindow()
    // Add longPress gesture recognizer
    let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(gesture:)))
    addGestureRecognizer(longPress)
  }

  // Handle longPress action
  func longPressAction(gesture: UILongPressGestureRecognizer) {
    if gesture.state == .began {
        guard let view = gesture.view else {
            return
        }
        initialCenter = gesture.location(in: view.superview)
    }
    else if gesture.state == .changed {
        guard let originalCenter = initialCenter else {
            return
        }

        guard let view = gesture.view else {
            return
        }

        let point = gesture.location(in: view.superview)

        // Calculate new center position
        var newCenter = view.center;
        newCenter.x += point.x - originalCenter.x;
        newCenter.y += point.y - originalCenter.y;

        // Update view center
        view.center = newCenter
    }
    else if gesture.state == .ended {
       ...
    }
}
Hari Kunwar
  • 1,661
  • 14
  • 10
2

You do not need to declare _priorPoint;

In my case, i only want the view to move horizontally so i'm only changing the x coordinate.

Here is my solution:

    if (longpressGestRec.state == UIGestureRecognizerStateChanged)
    {
        UIView *view = longpressGestRec.view;

        // Location of the touch within the view.
        CGPoint point = [longpressGestRec locationInView:view];

        // Calculate new X position based on the amount the gesture
        // has moved plus the size of the view we want to move.
        CGFloat newXLoc = (item.frame.origin.x + point.x) - (item.frame.size.width / 2);
        [item setFrame:CGRectMake(newXLoc,
                                  item.frame.origin.y,
                                  item.frame.size.width,
                                  item.frame.size.height)];
    }
Andrew
  • 1,344
  • 1
  • 12
  • 20
  • 3
    your solution only works for a `UIView` following the finger. Imagine you start the `UILongPress` from the corner of a picture and you want to swipe left, this picture would jump to the position of your finger. In my case, I had to use a `_priorPoint` solution. – Fabio Dec 10 '14 at 13:54
2

Thanks to Hari Kunwar for the Swift code, but the longPressAction function is not correctly defined.

Here's an improved version:

@objc func longPressAction(gesture: UILongPressGestureRecognizer)  {
    if gesture.state == UIGestureRecognizerState.began {
    }
    else if gesture.state == .changed {
        guard let view = gesture.view else {
            return
        }
        let location = gesture.location(in: self.view)
        view.center = CGPoint(x:view.center.x + (location.x - view.center.x),
                                          y:view.center.y + (location.y - view.center.y))
    }
    else if gesture.state == UIGestureRecognizerState.ended{
    }
}
HAVB
  • 1,858
  • 1
  • 22
  • 37
Lubomir.O
  • 21
  • 2