Combine longpress gesture and drag gesture together

29,128

Solution 1

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
    }
}

Solution 2

@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;
}

Solution 3

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 {
       ...
    }
}

Solution 4

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)];
    }

Solution 5

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{
    }
}
Share:
29,128
PJR
Author by

PJR

Check my Sample codes on Github: https://github.com/paritsohraval100 Cocoa Controls https://www.cocoacontrols.com/controls/pjr-scrollview-slider https://www.cocoacontrols.com/controls/pjr-nsstring-category https://www.cocoacontrols.com/controls/pjrsignaturedemo https://www.cocoacontrols.com/controls/pulseanimation Please check My Blog: http://iosdevblogs.blogspot.in/

Updated on July 09, 2022

Comments

  • PJR
    PJR almost 2 years

    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?

  • PJR
    PJR about 12 years
    i am using CGPoint translatedPoint = [(UILongPressGestureRecognizer*)sender translationInView:self.view]; but tor long press what i have to use ?
  • Srikar Appalaraju
    Srikar Appalaraju about 12 years
    try [yourView setFrame:CGRectMake(xCoord,yCoord,height,width)]
  • PJR
    PJR about 12 years
    but by this how can i get translatedPoint
  • Srikar Appalaraju
    Srikar Appalaraju about 12 years
    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.
  • Fabio
    Fabio over 9 years
    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.
  • Martin
    Martin almost 8 years
    @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]
  • Munib
    Munib over 7 years
    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!
  • RanLearns
    RanLearns about 6 years
    what do you set priorPoint to initially?
  • rob mayoff
    rob mayoff about 6 years
    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.
  • RanLearns
    RanLearns about 6 years
    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
    RanLearns about 6 years
    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 was helpful in providing a solution to recognize simultaneous gesture recognizers