I'm using a PanGestureRecognizer and in the UIGestureRecognizerStateChanged I let a view on the screen be moved by the users finger. I'm using that for a Tinder like swipe away gesture and I now want to limit the movement of the view to either the horizontal axis or the vertical axis, whatever direction the user started to swipe. I've been searching up and down but didn't find anything suitable here.
Is there any clever way to limit the axis movement, based on which direction the user started to swipe the view?
Thanks a bunch!
Update: Here's the current code that moves the view:
- (void)dragged:(UIPanGestureRecognizer *)gestureRecognizer
{
CGFloat xDistance = [gestureRecognizer translationInView:self].x;
CGFloat yDistance = [gestureRecognizer translationInView:self].y;
// xDistance = 0;
[parentView dragged:yDistance];
switch (gestureRecognizer.state) {
case UIGestureRecognizerStateBegan:{
self.originalPoint = self.center;
break;
};
case UIGestureRecognizerStateChanged:{
CGFloat rotationAngel = 0;
CGFloat scale = 1;//MAX(scaleStrength, 0.93);
CGAffineTransform transform = CGAffineTransformMakeRotation(rotationAngel);
CGAffineTransform scaleTransform = CGAffineTransformScale(transform, scale, scale);
self.transform = scaleTransform;
self.center = CGPointMake(self.originalPoint.x + xDistance, self.originalPoint.y + yDistance);
...
break;
};
case UIGestureRecognizerStateEnded: {
float moveDistAction = 60;
if (yDistance > moveDistAction) {
// view swiped down
...
} else if (yDistance < -moveDistAction) {//100 150
// view swiped up
...
} else {
// dragging cancelled
...
}
break;
};
case UIGestureRecognizerStatePossible:break;
case UIGestureRecognizerStateCancelled:break;
case UIGestureRecognizerStateFailed:break;
}
}
In gestureRecognizerShouldBegin: you can know that direction:
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
CGPoint translation = [gestureRecognizer translationInView:self.view];
self.isVerticalPan = fabs(translation.y) > fabs(translation.x); // BOOL property
return YES;
}
And then on the UIGestureRecognizerStateChanged you could do something like this, based on isVerticalPan property:
CGPoint translation = [gesture translationInView:self.view];
CGPoint displacement = (self.isVerticalPan) ? CGPointMake(0, translation.y) : CGPointMake(translation.x, 0);
self.viewToMove.transform = CGAffineTransformMakeTranslation(displacement.x, displacement.y);
You can do this by implementing the gestureRecognizerShouldBegin: delegate method. In the following implementation, I am checking for a roughly 20 degree horizontal swipe. But, you could check for either a horizontal or vertical swipe. (I would use some small angle, as it's very difficult for the user to move in exactly a straight line.)
- (BOOL) gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
// Ensure that the user is only panning mostly horizontally
// This allows the view to be placed in a scrollview that scrolls vertically
// Up/Down drags in the body of the view will be passed to the scroll view
if (gestureRecognizer == self.panGesture) {
CGPoint velocity = [self.panGesture velocityInView:self.panGesture.view];
double radian = atan(velocity.y/velocity.x);
double degree = radian * 180 / M_PI;
double thresholdAngle = 20.0;
if (fabs(degree) > thresholdAngle) {
return NO;
}
}
return YES;
}
Disclaimer: I'm pretty sure I found this solution somewhere here, but I couldn't find it. So, apologies to the original solver of this...
来源:https://stackoverflow.com/questions/28503095/limit-uiview-movement-to-only-vertical-or-horizontal-axis