2
votes

I'm having problems simply translating a view with UIPanGestureRecognizer while setting the UILabel's text to the gestures velocity.

I have been successfull translating a view with a pan gesture like this (with the help of IB):

- (IBAction)handleGesture:(UIPanGestureRecognizer *)sender

{   
    CGPoint translation = [sender translationInView:self.view];

    sender.view.center = CGPointMake(sender.view.center.x + translation.x, sender.view.center.y + translation.y);

    [sender setTranslation:CGPointMake(0, 0) inView:self.view];
} 

But when I add the following line to this method the view stops translating but the UILabel gets updated with the velocity:

self.myLabel.text = [NSString stringWithFormat:@"%@", [NSNumber numberWithInt:[sender velocityInView:self.roundShape].y]];

How can I fix this?

3

3 Answers

5
votes

Basically, the translation value you get from the Pan Gesture Recognizer is a relative value. Relative to the starting point when the gesture began recognizing the touch. So you want to do is hold onto the original point the gesture started at and apply the translation to that point, not to the view's current location.

- (void)gestureDidTranslate:(UIPanGestureRecognizer *)panGesture
{
    if([panGesture state] == UIGestureRecognizerStateBegan){
        self.originalPoint = self.movingView.center;
    }

    CGPoint translation = [panGesture translationInView:self.view];
    self.movingView.center = CGPointMake(self.originalPoint.x+translation.x, self.originalPoint.y+translation.y);
    self.label.text = NSStringFromCGPoint([panGesture velocityInView:self.view]);
}

I can't think of a time where you would want to zero-out the translation value to a recognizer while it is recognizing.

0
votes

Try this. Label update properly.

@implementation APViewController

- (void)viewDidLoad
{
  [super viewDidLoad];

  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(Pan:)];
  pan.minimumNumberOfTouches = 1;
  [_View addGestureRecognizer:pan];
}

- (void) Pan:(UIPanGestureRecognizer*)sender
{
  CGPoint translation = [sender translationInView:self.view];
  sender.view.center = CGPointMake(sender.view.center.x + translation.x, sender.view.center.y + translation.y);
  [sender setTranslation:CGPointMake(0, 0) inView:self.view];

  _Label.text = [NSString stringWithFormat:@"%f", [sender velocityInView:self.view].y];
}

@end

If you have an AUTOLAYOUT on your XIB, deselect it, because view don't move. Why? I don't know.

hope this helps.

0
votes

With Autolayout!

This is all possible using Interface Builder. Here is the code I used to do this:

@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonXConstraint;
@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonYConstraint;

Then hook up those IBOutlets to the Horizontal Constraint(X Position) and Vertical Constraint(Y Position) in the Interface Builder. Make sure that the Constraints are hooked up to the base view and not it's closest view.

Hook up a pan gesture and then use this following code to drag your object around:

- (IBAction)panPlayButton:(UIPanGestureRecognizer *)sender
{
    if(sender.state == UIGestureRecognizerStateBegan){

    } else if(sender.state == UIGestureRecognizerStateChanged){
        CGPoint translation = [sender translationInView:self.view];

        //Update the constraint's constant
        self.buttonXConstraint.constant += translation.x;
        self.buttonYConstraint.constant += translation.y;

        // Assign the frame's position only for checking it's fully on the screen
        CGRect recognizerFrame = sender.view.frame;
        recognizerFrame.origin.x = self.buttonXConstraint.constant;
        recognizerFrame.origin.y = self.buttonYConstraint.constant;

        // Check if UIImageView is completely inside its superView
        if(!CGRectContainsRect(self.view.bounds, recognizerFrame)) {
            if (self.buttonYConstraint.constant < CGRectGetMinY(self.view.bounds)) {
                self.buttonYConstraint.constant = 0;
            } else if (self.buttonYConstraint.constant + CGRectGetHeight(recognizerFrame) > CGRectGetHeight(self.view.bounds)) {
                self.buttonYConstraint.constant = CGRectGetHeight(self.view.bounds) - CGRectGetHeight(recognizerFrame);
            }

            if (self.buttonXConstraint.constant < CGRectGetMinX(self.view.bounds)) {
                self.buttonXConstraint.constant = 0;
            } else if (self.buttonXConstraint.constant + CGRectGetWidth(recognizerFrame) > CGRectGetWidth(self.view.bounds)) {
                self.buttonXConstraint.constant = CGRectGetWidth(self.view.bounds) - CGRectGetWidth(recognizerFrame);
            }
        }

        //Layout the View
        [self.view layoutIfNeeded];
    } else if(sender.state == UIGestureRecognizerStateEnded){

    }

    [sender setTranslation:CGPointMake(0, 0) inView:self.view];
}

I have added code in there to check the frame and make sure that it's not going outside the view. If you want to allow the object to be partially off the screen, feel free to take it out.

This took a little bit of time for me to realize that it was the use of AutoLayout that was resetting the view but constraints will do what you need here!