UIPanGestureRecognizer - Only vertical or horizontal
I figured it out creating a subclass of UIPanGestureRecognizer
DirectionPanGestureRecognizer:
#import <Foundation/Foundation.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
typedef enum {
DirectionPangestureRecognizerVertical,
DirectionPanGestureRecognizerHorizontal
} DirectionPangestureRecognizerDirection;
@interface DirectionPanGestureRecognizer : UIPanGestureRecognizer {
BOOL _drag;
int _moveX;
int _moveY;
DirectionPangestureRecognizerDirection _direction;
}
@property (nonatomic, assign) DirectionPangestureRecognizerDirection direction;
@end
DirectionPanGestureRecognizer.m:
#import "DirectionPanGestureRecognizer.h"
int const static kDirectionPanThreshold = 5;
@implementation DirectionPanGestureRecognizer
@synthesize direction = _direction;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
if (self.state == UIGestureRecognizerStateFailed) return;
CGPoint nowPoint = [[touches anyObject] locationInView:self.view];
CGPoint prevPoint = [[touches anyObject] previousLocationInView:self.view];
_moveX += prevPoint.x - nowPoint.x;
_moveY += prevPoint.y - nowPoint.y;
if (!_drag) {
if (abs(_moveX) > kDirectionPanThreshold) {
if (_direction == DirectionPangestureRecognizerVertical) {
self.state = UIGestureRecognizerStateFailed;
}else {
_drag = YES;
}
}else if (abs(_moveY) > kDirectionPanThreshold) {
if (_direction == DirectionPanGestureRecognizerHorizontal) {
self.state = UIGestureRecognizerStateFailed;
}else {
_drag = YES;
}
}
}
}
- (void)reset {
[super reset];
_drag = NO;
_moveX = 0;
_moveY = 0;
}
@end
This will only trigger the gesture if the user starts dragging in the selected behavior. Set the direction property to a correct value and you are all set.
Limit UIView movement to only vertical or horizontal axis
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);
UIPanGesture recognizer swiping only in one direction
your same code just one changes in your UIGestureRecognizer method replace with this code and your problem solve. only left to right side swap work on your tableview cell . any query regrading this just drop comment below.
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
let translation = panGestureRecognizer.translation(in: superview!)
if translation.x >= 0 {
return true
}
return false
}
return false
}
Good Luck.
Keep coding.
Horizontal Pan Inside Vertical Scrollview
You could use one of the UIGestureRecognizerDelegate
methods like gestureRecognizerShouldBegin:
to specify which pan gesture is triggered in which situation.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
// If the gesture is a pan, determine whether it starts out more
// horizontal than vertical than act accordingly
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer *panGestureRecognizer = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint velocity = [panGestureRecognizer velocityInView:self.view];
if (gestureRecognizer == self.scrollView.panGestureRecognizer) {
// For the vertical scrollview, if it's more vertical than
// horizontal, return true; else false
return fabs(velocity.y) > fabs(velocity.x);
} else {
// For the horizontal pan view, if it's more horizontal than
// vertical, return true; else false
return fabs(velocity.y) < fabs(velocity.x);
}
}
else
return YES;
}
Stop UIPanGestureRecognizer from moving UIView vertically when inside a UIScrollView
Try disabling scrolling on state begun and re-enabling it on state ended.
[scrollView setScrollEnabled:NO]; // in case UIGestureRecognizerStateBegan
[scrollView setScrollEnabled:YES]; // in case UIGestureRecognizerStateEnded
Horizontal scrolling UIScrollView with vertical pan gesture
I think this will be difficult if you want to use a pan gesture because of the scroll view's use of those gestures. However, if you could use a swipe, it is easy to implement.
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
swipe.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp;
[self.scrollView addGestureRecognizer:swipe];
I tested this, and it worked fine to call the handler, and you don't need to disable the scroll view's pan gesture recognizer (in my test, the scroll view was tall enough and the content short enough that there was no vertical scrolling -- I don't know if this is necessary or not).
Simultaneously recognising UIPanGestureRecognizer, UIRotationGestureRecognizer, and UIPinchGestureRecognizer
Give this a try -- seems to work well for simultaneous Pan / Rotate / Scale:
class PinchPanRotateViewController: UIViewController, UIGestureRecognizerDelegate {
let testView: UILabel = {
let v = UILabel()
v.text = "TEST"
v.textAlignment = .center
v.textColor = .yellow
v.layer.cornerRadius = 4.0
v.layer.borderWidth = 4.0
v.layer.borderColor = UIColor.red.cgColor
v.layer.masksToBounds = true
//Enable multiple touch and user interaction
v.isUserInteractionEnabled = true
v.isMultipleTouchEnabled = true
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
view.addSubview(testView)
testView.frame = CGRect(x: 0, y: 0, width: 240, height: 180)
testView.center = view.center
//add pan gesture
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
gestureRecognizer.delegate = self
testView.addGestureRecognizer(gestureRecognizer)
//add pinch gesture
let pinchGesture = UIPinchGestureRecognizer(target: self, action:#selector(handlePinch(_:)))
pinchGesture.delegate = self
testView.addGestureRecognizer(pinchGesture)
//add rotate gesture.
let rotate = UIRotationGestureRecognizer.init(target: self, action: #selector(handleRotate(_:)))
rotate.delegate = self
testView.addGestureRecognizer(rotate)
}
@objc func handlePan(_ pan: UIPanGestureRecognizer) {
if pan.state == .began || pan.state == .changed {
guard let v = pan.view else { return }
let translation = pan.translation(in: self.view)
v.center = CGPoint(x: v.center.x + translation.x, y: v.center.y + translation.y)
pan.setTranslation(CGPoint.zero, in: self.view)
}
}
@objc func handlePinch(_ pinch: UIPinchGestureRecognizer) {
guard let v = pinch.view else { return }
v.transform = v.transform.scaledBy(x: pinch.scale, y: pinch.scale)
pinch.scale = 1
}
@objc func handleRotate(_ rotate: UIRotationGestureRecognizer) {
guard let v = rotate.view else { return }
v.transform = v.transform.rotated(by: rotate.rotation)
rotate.rotation = 0
}
func gestureRecognizer(_: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
return true
}
}
Detect vertical panning in UITableView
UITableView
is a subclass of UIScrollview
so you can get hold of it's panGestureRecognizer
and add your own action targets.
Related Topics
Xcode 6 Keeps Renaming My App's Directory in iOS8 Simulator After Each Run
Error: Error Domain=Nsurlerrordomain Code=-1001 "The Request Timed Out."
Restricting App Installations from Appstore Only to Users with iPhone 5/5S/5C
Xcode iOS Project Only Shows "My MAC 64-Bit" But Not Simulator or Device
What Should Image Sizes Be at @1X, @2X and @3X in Xcode
Xcode 8 "The Aps-Environment Entitlement Is Missing from the App's Signature" on Submit
Custom Interactive Transition Animation
Send Programmatically Sms on Jailbreak Device
Expand Uilabel Inside Uitableview with "More" Button Like Instagram
Create a Copy of a Uiview in Swift
Removing Duplicates from Array of Custom Objects Swift
-Canopenurl: Failed for Url: "Fbauth2:/" (Osstatus Error -10814.)"
Uiview - How to Get Notified When the View Is Loaded
Using Custom Font in a Uiwebview
How to Disable Uitextfield Editing But Still Accept Touch