Good day. Just started to learn gestures in iOS, I run the tutorial http://www.appcoda.com/ios-gesture-recognizers/ . I got to Pan Gesture Recognizer, and there was a problem: after assigning vertical and horizontal speed values ​​to labels, the gesture “breaks”. UIVIew no longer moves smoothly with the mouse cursor, but jumps to the place where the mouse cursor stopped. Label values ​​are updated without problems. Below is the code that implements the movement of the test view:

PanViewController.h @interface PanViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *testView; @property (weak, nonatomic) IBOutlet UILabel *horizontalVelocityLabel; @property (weak, nonatomic) IBOutlet UILabel *verticalVelocityLabel; @end PanViewController.m @interface PanViewController () - (void)moveViewWithGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer; @end @implementation PanViewController - (void)viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveViewWithGestureRecognizer:)]; [self.testView addGestureRecognizer:panGestureRecognizer]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)moveViewWithGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer { CGPoint touchLocation = [panGestureRecognizer locationInView:self.view]; self.testView.center = touchLocation; 

After adding the following lines to the last method, there is a problem with incorrect execution of the drag gesture, although no errors occur:

  CGPoint velocity = [panGestureRecognizer velocityInView:self.view]; self.horizontalVelocityLabel.text = [NSString stringWithFormat:@"Horizontal Velocity: %.2f points/sec", velocity.x]; self.verticalVelocityLabel.text = [NSString stringWithFormat:@"Vertical Velocity: %.2f points/sec", velocity.y]; } 

How do I fix this "breakdown"? I really want to understand what I am doing wrong, and not to continue further studies without understanding the problem. Thank you in advance.

    2 answers 2

    This is because when you move, you put the UIView in the center, and you need to calculate and set the frame:

     - (void)moveViewWithGestureRecognizer:(UIPanGestureRecognizer *)panGestureRecognizer { //CGPoint touchLocation = [panGestureRecognizer locationInView:self.view]; //self.testView.center = touchLocation; CGPoint translation = [panGestureRecognizer translationInView:panGestureRecognizer.view]; CGRect newFrame = self.testView.frame; newFrame.origin.y = newFrame.origin.y + translation.y; newFrame.origin.x = newFrame.origin.x + translation.x; self.testView.frame = newFrame; [panGestureRecognizer setTranslation:CGPointZero inView:panGestureRecognizer.view]; CGPoint velocity = [panGestureRecognizer velocityInView:self.view]; self.horizontalVelocityLabel.text = [NSString stringWithFormat:@"Horizontal Velocity: %.2f points/sec", velocity.x]; self.verticalVelocityLabel.text = [NSString stringWithFormat:@"Vertical Velocity: %.2f points/sec", velocity.y]; } 

    This code will only work if Autolayout is turned off. If Autolayout is enabled, then for this you can see this discussion https://stackoverflow.com/questions/16129988/ios-dragged-view-is-jumping-back-to-original-position-auto-layout-combined

    You can see the implementation of my code without autolayout: https://cloud.mail.ru/public/2g1Y/EC19pnX2P

    • 2
      All because you are using autolayout. There is a topic about this: stackoverflow.com/questions/16129988/… - runia
    • one
      @NataliaTatarinteva You can see the implementation of my code without autolayout: cloud.mail.ru/public/2g1Y/EC19pnX2P If you want to use along with autolayout, then look at the link I threw a comment above - runia
    • 2
      Indeed, turning off autolayout in Main.storyboard fixes the problem. - Anastasia
    • 3
      @NataliaTatarinteva, thank you, but my comment is really based on the runia comment (second from the top), I just specified how to turn off autolayout. I offer runia to place your comment in another answer :) - Anastasia
    • one
      @Anastasia thanks;) I added the ending to my answer under the code so that everyone could understand for the future :) NataliaTatarinteva can mark my answer with the right one so as not to produce a bunch of answers. Good luck! - runia

    Better not use frame or center , use NSLayoutConstaint for this

    create

     @property (weak, nonatomic) IBOutlet NSLayoutConstaint *testViewLeft; 

    move it further:

     self.testViewLeft.constant = newValue; [self.view layoutIfNeeded]; 

    To make this happen to the animation, put layoutIfNeeded() in the animation block.

     [UIView animateWithDuration: 0.1 animations: ^{ [self.view layoutIfNeeded]; } completion: nil]; 

    save the offset of the start point of the gesture from the edge of the view, this will help make the movement smoother at the beginning

     @property (nonatomic) CGFloat panOffset; 

    besides, in action check the state of the gesture:

     - (void)panGestureStateChanged:(UIPanGestureRecognizer *)sender { switch (sender.state) { case UIGestureRecognizerStateBegan: self.panOffset = sender.locationInView(contentContainerView).x break; case UIGestureRecognizerStateChanged: CGFloat touchPoint = [sender locationInView:view]; CGFloat newConstant = touchPoint.x - offset; self.testViewLeft.constant = newConstant; [UIView animateWithDuration:0.03 animations:^{ [self.view layoutIfNeeded]; } completion: nil]; break; case UIGestureRecognizerStateEnded: panOffset = 0; break; default: break; } } 

    it will still be useful for UIGestureRecognizerDelegate to become and implement a method to control when to start the gesture, and when not:

     - (BOOL)gestureRecognizerShouldBegin(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer == self.myPanGesture) { return (someGestureBeginConditions > 0); } return true; }