UIPANGestureRecognizer - केवल ऊर्ध्वाधर या क्षैतिज


146

मेरे पास एक दृश्य है जिसमें UIPanGestureRecognizerदृश्य को लंबवत रूप से खींचने के लिए है। इसलिए पहचानकर्ता कॉलबैक में, मैं इसे स्थानांतरित करने के लिए केवल y-निर्देशांक अद्यतन करता हूं। इस दृश्य के पर्यवेक्षण में, वह एक UIPanGestureRecognizerदृश्य को क्षैतिज रूप से खींचेगा, बस x- समन्वय को अद्यतन करेगा।

समस्या यह है कि पहले UIPanGestureRecognizerदृश्य को लंबवत स्थानांतरित करने के लिए घटना को ले जा रहा है, इसलिए मैं पर्यवेक्षी हावभाव का उपयोग नहीं कर सकता।

मैंने कोशिश की है

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
 shouldRecognizeSimultaneouslyWithGestureRecognizer:
                            (UIGestureRecognizer *)otherGestureRecognizer;

और दोनों काम करेंगे, लेकिन मैं ऐसा नहीं चाहता। मैं चाहता हूं कि क्षैतिज रूप से केवल तभी पता लगाया जाए जब आंदोलन स्पष्ट रूप से क्षैतिज है। अगर UIPanGestureRecognizerदिशा की संपत्ति होती तो यह बहुत अच्छा होता ।

मैं इस व्यवहार को कैसे प्राप्त कर सकता हूं? मुझे डॉक्स बहुत भ्रामक लगते हैं, इसलिए हो सकता है कि कोई इसे यहां बेहतर तरीके से समझा सके।


यदि आपने समाधान निकाला है, तो अपने स्वयं के प्रश्न का उत्तर देना और उत्तर स्वीकार करना ठीक है।
jtbandes

@JoeBlow वास्तव में? तो, हो सकता है कि आपने अनुवाद और वेग के संकेत प्राप्त करने के लिए स्वाइप जेस्चर की श्रेणी बनाई हो?
रोमन ट्रूबा

2
मुझे समझ नहीं आ रहा है कि आप क्या कह रहे हैं। यदि आप एक क्षैतिज स्वाइप का पता लगाना चाहते हैं , तो यह ऑपरेटिंग सिस्टम के लिए पूरी तरह से और पूरी तरह से अंतर्निहित है । सभी काम पूरी तरह से और पूरी तरह से आपके लिए किए जाते हैं। आपको करने की ज़रूरत है ... कुछ नहीं! :) बस इस उदाहरण में कोड की दो पंक्तियों में पेस्ट करें .. stackoverflow.com/a/20988648/294884 ध्यान दें कि आप केवल "" दाएं केवल "या" दोनों "चुन सकते हैं।
फेटी

जवाबों:


212

बस इसे वर्टिकल पैन जेस्चर पहचानकर्ता के लिए करें, यह मेरे लिए काम करता है:

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
    CGPoint velocity = [panGestureRecognizer velocityInView:someView];
    return fabs(velocity.y) > fabs(velocity.x);
}

और स्विफ्ट के लिए:

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIPanGestureRecognizer) -> Bool {
    let velocity = gestureRecognizer.velocity(in: someView)
    return abs(velocity.x) > abs(velocity.y)
}

3
यह कोशिश की, लेकिन अनुवाद अक्सर == (0,0) है, इसलिए यह सटीक नहीं है
zxcat

12
जब वेग (दृश्य) का प्रयोग किया जाता है, तो यह स्पष्ट नहीं होता है।
cbh2000

1
@ cbh2000 मैंने velocityInViewइसके बजाय उपयोग करने के लिए उत्तर अपडेट किया translationInView
हिजाज़ी

19
@JoeBlow एक UISwipeGestureRecognizer एक स्वाइप जेस्चर के जवाब में एक संक्रमण को दूर करने का एक आसान तरीका है, लेकिन यह एक असतत इशारा है। यदि कोई व्यक्ति एक सतत दृष्टिकोण की तलाश में है - एक इशारे के साथ एक संक्रमण को चेतन करने के लिए - एक UIPanGestureRecognizer जाने का रास्ता है।
लेवी मैक्लम

यह चतुर समाधान है
Jakub Truhlá clever

79

मैंने उपलब्ध कराए गए उत्तर @LocoMike की तरह उपवर्ग के साथ एक समाधान बनाया, लेकिन @Hejazi द्वारा प्रदान किए गए प्रारंभिक वेग के माध्यम से अधिक प्रभावी पहचान तंत्र का उपयोग किया। मैं स्विफ्ट का उपयोग भी कर रहा हूं, लेकिन अगर वांछित हो तो ओबज-सी का अनुवाद करना आसान होना चाहिए।

अन्य समाधानों पर लाभ:

  • अन्य उपवर्ग समाधानों की तुलना में सरल और अधिक संक्षिप्त। प्रबंधन करने के लिए कोई अतिरिक्त राज्य नहीं।
  • दिशा का पता बेगन कार्रवाई भेजने से पहले होता है, इसलिए गलत दिशा में स्वाइप करने पर आपके पैन जेस्चर चयनकर्ता को कोई संदेश नहीं मिलता है।
  • प्रारंभिक दिशा निर्धारित होने के बाद, दिशा तर्क से परामर्श नहीं किया जाता है। यह आपके पहचानकर्ता को सक्रिय करने के आम तौर पर वांछित व्यवहार के परिणामस्वरूप होता है यदि प्रारंभिक दिशा सही है, लेकिन उपयोगकर्ता द्वारा पूरी तरह से दिशा के साथ यात्रा नहीं करने पर यह शुरू होने के बाद इशारे को रद्द नहीं करता है।

यहाँ कोड है:

import UIKit.UIGestureRecognizerSubclass

enum PanDirection {
    case vertical
    case horizontal
}

class PanDirectionGestureRecognizer: UIPanGestureRecognizer {

    let direction: PanDirection

    init(direction: PanDirection, target: AnyObject, action: Selector) {
        self.direction = direction
        super.init(target: target, action: action)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)

        if state == .began {
            let vel = velocity(in: view)
            switch direction {
            case .horizontal where fabs(vel.y) > fabs(vel.x):
                state = .cancelled
            case .vertical where fabs(vel.x) > fabs(vel.y):
                state = .cancelled
            default:
                break
            }
        }
    }
}

उपयोग का उदाहरण:

let panGestureRecognizer = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(handlePanGesture(_:)))
panGestureRecognizer.cancelsTouchesInView = false
self.view.addGestureRecognizer(panGestureRecognizer)

func handlePanGesture(_ pan: UIPanGestureRecognizer) {
    let percent = max(pan.translation(in: view).x, 0) / view.frame.width

    switch pan.state {
    case .began:
    ...
}

4
यह बिल्कुल सबसे अच्छा जवाब है। यह बहुत बुरा है कि Apple ने इस तरह की कार्यक्षमता को नहीं जोड़ा है UIPanGestureRecognizer
NRitH

क्या आप एक उपयोग उदाहरण प्रदान कर सकते हैं?
user82395214

ये बहुत प्यारी है! धन्यवाद! पूरी तरह से काम करता है जब दोनों क्षैतिज और ऊर्ध्वाधर स्टैकिंग: let horizontalPanRecognizer = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(handleHorizontalPanGesture(recognizer:))) self.view?.addGestureRecognizer(horizontalPanRecognizer); let verticalPanRecognizer = PanDirectionGestureRecognizer(direction: .vertical, target: self, action: #selector(handleVerticalPanGesture(recognizer:))) self.view?.addGestureRecognizer(verticalPanRecognizer);
हान

ओह यह कमाल है! धन्यवाद!
बारां इमर

51

मुझे लगा कि यह 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

यह केवल इशारे को ट्रिगर करेगा यदि उपयोगकर्ता चयनित व्यवहार में खींचना शुरू कर देता है। दिशा संपत्ति को एक सही मान पर सेट करें और आप सभी सेट हैं।


मुझे लगता है कि 'रीसेट' को शुरू में नहीं बुलाया जा रहा है। एक initWithTarget:action:विधि को जोड़ा और रीसेट कहा जाता है और सब कुछ ठीक था।
कोलिंका

5
वर्तमान कार्यान्वयन में DirectionPanGestureRecognizerतेज ड्रग्स की अवहेलना करेंगे, जब तक कि आप सेट kDirectionPanThreshold = 20या तो नहीं करते हैं, जिस स्थिति में यह गलत अलार्म दे सकता है। मैं क्रमशः क्षैतिज मामले को बदलने और बदलने के abs(_moveX) > abs(_moveY)बजाय सुझाव देता हूं abs(_moveX) > kDirectionPanThreshold
डेनिस क्रुत

2
मुझे इसे जोड़ना चाहिए यह मेरे लिए भी मददगार था, लेकिन मुझे ट्रिगर करने के लिए पैन जेस्चर पहचानकर्ता को जोड़ने के लिए मुझे जो भी जोड़ना था, अगर _drag = YESमैं लाइन के नीचे के दूसरे भाग में था, तो मैंने कहाself.state = UIGestureRecognizerStateChanged;
bolnad

13

मैंने UIPanGestureRecognizer के साथ वैध रूप से वैध क्षेत्र को बाधित करने का प्रयास किया।

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {

        UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
        CGPoint velocity = [panGesture velocityInView: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;
}

तब, केवल दहलीज के भीतर स्वाइप करने से क्षैतिज डिग्री इस पैन के हावभाव को ट्रिगर कर सकती है।


2
बहुत बढ़िया जवाब। जब मैं UIScrollView इशारों और नियमित इशारों को मिला रहा था तो इससे मुझे वास्तव में मदद मिली। मुझे लगता है कि उदाहरण "थ्रेशोल्ड" के बजाय "थ्रेसहोल्ड" कहने का मतलब है। और आपको शायद ही कभी atan () का उपयोग करना चाहिए क्योंकि यह NAN का उत्पादन कर सकता है। इसके बजाय atan2 () का उपयोग करें।
ब्रेनवेयर

9

स्विफ्ट 3.0 का जवाब: सिर्फ हैंडल ही वर्टिकल जेस्चर देता है

    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let pan = gestureRecognizer as? UIPanGestureRecognizer {
        let velocity = pan.velocity(in: self)
        return fabs(velocity.y) > fabs(velocity.x)
    }
    return true

}

6

निम्नलिखित समाधान ने मेरी समस्या हल कर दी:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([gestureRecognizer.view isEqual:self.view] && [otherGestureRecognizer.view isEqual:self.tableView]) {
        return NO;
    }
    return YES;
}

यह वास्तव में सिर्फ जाँच है कि पैन मुख्य दृश्य या तालिका दृश्य पर जा रहा है या नहीं।


3
क्यों कॉल -isEqual: तुलना करने के लिए कि क्या दो विचार समान हैं? एक साधारण पहचान जाँच पर्याप्त होनी चाहिए। gestureRecognizer.view == self.view
ओपनफ्रॉग

6

आलसी के लिए ली के जवाब का 3 संस्करण स्विफ्ट

import UIKit
import UIKit.UIGestureRecognizerSubclass

enum PanDirection {
    case vertical
    case horizontal
}

class UIPanDirectionGestureRecognizer: UIPanGestureRecognizer {

    let direction : PanDirection

    init(direction: PanDirection, target: AnyObject, action: Selector) {
        self.direction = direction
        super.init(target: target, action: action)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)

        if state == .began {

            let vel = velocity(in: self.view!)
            switch direction {
            case .horizontal where fabs(vel.y) > fabs(vel.x):
                state = .cancelled
            case .vertical where fabs(vel.x) > fabs(vel.y):
                state = .cancelled
            default:
                break
            }
        }
    }
}

4

मैंने ली गुडरिक का जवाब लिया और इसे बढ़ाया क्योंकि मुझे विशेष रूप से एकल दिशा पैन की आवश्यकता थी। इसे इस तरह उपयोग करें:let pan = PanDirectionGestureRecognizer(direction: .vertical(.up), target: self, action: #selector(handleCellPan(_:)))

मैंने इसे कुछ स्पष्ट करने के लिए कुछ टिप्पणी भी जोड़ दी कि वास्तव में क्या निर्णय लिए जा रहे हैं।

import UIKit.UIGestureRecognizerSubclass

enum PanVerticalDirection {
    case either
    case up
    case down
}

enum PanHorizontalDirection {
    case either
    case left
    case right
}

enum PanDirection {
    case vertical(PanVerticalDirection)
    case horizontal(PanHorizontalDirection)
}

class PanDirectionGestureRecognizer: UIPanGestureRecognizer {

    let direction: PanDirection

    init(direction: PanDirection, target: AnyObject, action: Selector) {
        self.direction = direction
        super.init(target: target, action: action)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)

        if state == .began {
            let vel = velocity(in: view)
            switch direction {

            // expecting horizontal but moving vertical, cancel
            case .horizontal(_) where fabs(vel.y) > fabs(vel.x):
                state = .cancelled

            // expecting vertical but moving horizontal, cancel
            case .vertical(_) where fabs(vel.x) > fabs(vel.y):
                state = .cancelled

            // expecting horizontal and moving horizontal
            case .horizontal(let hDirection):
                switch hDirection {

                    // expecting left but moving right, cancel
                    case .left where vel.x > 0: state = .cancelled

                    // expecting right but moving left, cancel
                    case .right where vel.x < 0: state = .cancelled
                    default: break
                }

            // expecting vertical and moving vertical
            case .vertical(let vDirection):
                switch vDirection {
                    // expecting up but moving down, cancel
                    case .up where vel.y > 0: state = .cancelled

                    // expecting down but moving up, cancel
                    case .down where vel.y < 0: state = .cancelled
                    default: break
                }
            }
        }
    }
}

में त्रुटि override func touchesMoved- Method does not override any method from its superclass
अंबस्वि

@Annjawn आपको "आयात UIKit.UIGestureRecognizerSubclass" का उपयोग करना होगा
shawnynicole

ठीक। मुझे इसकी जानकारी नहीं थी। मुझे लगा कि UIKit का आयात स्वचालित रूप से इसे आयात करेगा। मै उसे करने की एक कोशिश तो करूंगा।
अनीबस

2

आप इसके UIViewमाध्यम से दिशा को खींच सकते हैं UIPanGestureRecognizer। कृपया कोड का पालन करें।

 - (void)viewDidLoad {
    [super viewDidLoad];
    flipFoward = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doFlipForward:)];
    [flipFoward setMaximumNumberOfTouches:1];
    [flipFoward setMinimumNumberOfTouches:1];
    [flipFoward setDelegate:self];
    [self.view addGestureRecognizer:flipFoward];
    flipBack = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doFlipBack:)];
    [flipBack setMaximumNumberOfTouches:1];
    [flipBack setMinimumNumberOfTouches:1];
    [flipBack setDelegate:self];
    [self.view addGestureRecognizer:flipBack];
}

#pragma mark -
#pragma mark RESPONDER

-(void)doFlipForward:(UIGestureRecognizer *)aGestureRecognizer{
    NSLog(@"doFlipForward");
    if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateBegan) {
        NSLog(@"UIGestureRecognizerStateBegan");
    }
    if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateChanged) {
        NSLog(@"UIGestureRecognizerStateChanged");
    }
    if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateEnded) {
        NSLog(@"UIGestureRecognizerStateEnded");
    }
}

-(void)doFlipBack:(UIGestureRecognizer *)aGestureRecognizer{
    NSLog(@"doFlipBack");
    if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateBegan) {
        NSLog(@"UIGestureRecognizerStateBegan1");
    }
    if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateChanged) {
        NSLog(@"UIGestureRecognizerStateChanged1");
    }
    if([(UIPanGestureRecognizer*)aGestureRecognizer state] == UIGestureRecognizerStateEnded) {
        NSLog(@"UIGestureRecognizerStateEnded1");
    }
}

#pragma mark -
#pragma mark DELEGATE

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    CGSize size = [self.view bounds].size;
    CGFloat touchX = [gestureRecognizer locationInView:self.view].x;
    if((gestureRecognizer == flipFoward) 
       && touchX >= (size.width - 88.0f))
    {
        return YES;
    }
    if((gestureRecognizer == flipBack)
       && touchX <= 88.0f)
    {
        return YES;
    }
    return NO;
}

वास्तव में यह अच्छा समाधान नहीं है क्योंकि केवल बाएं से 88 अंक पैन करने में सक्षम हैं।
बोरुत टोमाज़िन

2

स्विफ्ट 4.2

समाधान केवल क्षैतिज रूप से, समान रूप से पैन जेस्चर का समर्थन करने के लिए है।

let pan = UIPanGestureRecognizer(target: self, action: #selector(test1))
pan.cancelsTouchesInView = false
panView.addGestureRecognizer(pan)

समाधान 1 :

@objc func panAction(pan: UIPanGestureRecognizer) {

        let velocity = pan.velocity(in: panView)
        guard abs(velocity.y) > abs(velocity.x) else {
            return
        }
}

समाधान 2:

  [UISwipeGestureRecognizer.Direction.left, .right].forEach { direction in
        let swipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeAction))
        swipe.direction = direction
        panView.addGestureRecognizer(swipe)
        pan.require(toFail: swipe)
    }

फिर स्वाइप जेस्चर पैन गेस्चर को निगल जाएगा। बेशक, आपको कुछ भी करने की आवश्यकता नहीं है swipeAction


1

यहाँ है कि मैं कैसे हल किया है:

पहले मैंने इसके साथ-साथ पैनग्योरचर रिकॉग्निशन को सक्षम किया।

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {

return YES;

तब मैं क्षैतिज और ऊर्ध्वाधर पैन इशारों को जमा करता हूं (संचायक NSMutableArray गुण है):

- (void)verticalPan :(UIPanGestureRecognizer *) sender {

CGPoint touch  = [sender translationInView:self];
NSValue *value = [NSValue valueWithCGPoint:touch];
[accumulator addObject:value];

int firstXObjectValue = (int)[[accumulator objectAtIndex:0] CGPointValue].x ;
int lastXObjectValue =  (int)[[accumulator lastObject] CGPointValue].x;

int firstYObjectValue = (int)[[accumulator objectAtIndex:0] CGPointValue].y;
int lastYObjectValue =  (int)[[accumulator lastObject] CGPointValue].y;

if (abs(lastYObjectValue - firstYObjectValue) < 4 && abs(lastXObjectValue - firstXObjectValue) > 4) {
    NSLog(@"Horizontal Pan");

    //do something here
}
else if (abs(lastYObjectValue - firstYObjectValue) > 4 && abs(lastXObjectValue - firstXObjectValue) < 4){
    NSLog(@"Vertical Pan");

    //do something here
}

if (accumulator.count > 3)
    [accumulator removeAllObjects];

मैंने यहां एक उदाहरण दिया:

स्क्रॉलव्यू में कस्टम पैन जोड़ें


1
let pangesture = UIPanGestureRecognizer(target: self, action: "dragview:")
yourview.addGestureRecognizer(pangesture)


func dragview(panGestureRecognizer:UIPanGestureRecognizer)
{
    let touchlocation = panGestureRecognizer.locationInView(parentview)
    yourview.center.y = touchlocation.y //x for horizontal 
}

1

आप सरल का उपयोग कर सकते हैं panGestureRecognizer। उपयोग pandirectionregognizerया सामान की आवश्यकता नहीं है । translationInview नीचे कोड चाल खींचें दृश्य के केवल y मान का उपयोग केवल ऊपर और नीचे करें

- (void)gesturePan_Handle:(UIPanGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateChanged) {
        CGPoint translation = [gesture translationInView:gesture.view];
        recognizer.view.center = CGPointMake(recognizer.view.center.x, recognizer.view.center.y + translation.y);
        [gesture setTranslation:CGPointMake(0, 0) inView:gesture.view];
    }
}

यह कोड केवल दृश्य को पैन करता है। कोई भी दिशा-निर्देश लॉक नहीं किया गया है।
जकिशाहीन

1
- (void)dragAction:(UIPanGestureRecognizer *)gesture{
      UILabel *label = (UILabel *)gesture.view;
      CGPoint translation = [gesture translationInView:label];
     label.center = CGPointMake(label.center.x + translation.x,
                             label.center.y + 0);
    [gesture setTranslation:CGPointZero inView:label];}

मैंने PanGestureRecognizer @selector एक्शन मेथड को उस ऑब्जेक्ट के लिए बनाया जिसमें केवल क्षैतिज स्क्रॉलिंग की आवश्यकता थी।

 UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(smileyDragged:)];
    [buttonObject addGestureRecognizer:gesture];

1

स्विफ्ट रास्ता

override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
        return isVerticalGesture(panGestureRecognizer)
    }
    return false
}

private func isVerticalGesture(_ recognizer: UIPanGestureRecognizer) -> Bool {
    let translation = recognizer.translation(in: superview!)
    if fabs(translation.y) > fabs(translation.x) {
        return true
    }
    return false
}

0

आप सभी उपयोगकर्ताओं को वहाँ से बाहर करने के लिए, यह काम करेगा :)

import Foundation
import UIKit.UIGestureRecognizerSubclass


class DirectionPanGestureRecognizer: UIPanGestureRecognizer {

let kDirectionPanThreshold = CGFloat(5)
var drag = true
var moveX = CGFloat(0)
var moveY = CGFloat(0)

override init(target: AnyObject, action: Selector) {
    super.init(target: target, action: action)
}

override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
    super.touchesMoved(touches, withEvent: event)
    if state == .Failed {
        return
    }

    let nowPoint = touches.anyObject()?.locationInView(view)
    let prevPoint = touches.anyObject()?.previousLocationInView(view)
    moveX += prevPoint!.x - nowPoint!.x
    moveY += prevPoint!.y - nowPoint!.y
    if !drag {
        if abs(moveX) > kDirectionPanThreshold {
            state = .Failed
        } else {
            drag = true
        }

    }

}

 override func reset() {
    super.reset()
    moveX = 0
    moveY = 0
    drag = false
}




}

0

मैंने ली गुडरिच द्वारा एक उत्कृष्ट उत्तर लिया और स्विफ्ट 3 में पोर्ट किया

import UIKit
import UIKit.UIGestureRecognizerSubclass

enum PanDirection {
    case vertical
    case horizontal
}

class PanDirectionGestureRecognizer: UIPanGestureRecognizer {

    let direction : PanDirection

    init(direction: PanDirection, target: AnyObject, action: Selector) {
        self.direction = direction
        super.init(target: target, action: action)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {

        super.touchesMoved(touches, with: event)

        if state == .began {

            let vel = velocity(in: self.view!)

            switch direction {

            case .horizontal where fabs(vel.y) > fabs(vel.x):
                state = .cancelled

            case .vertical where fabs(vel.x) > fabs(vel.y):
                state = .cancelled

            default:
                break

            }

        }
    }
}

0

मैं अपने दृष्टिकोण को साझा करना पसंद करूंगा क्योंकि अन्य सभी दृष्टिकोण UIGestureRecognizerDelegateया तो या उपवर्ग पर आधारित हैंUIPanGestureRecognizer

मेरा दृष्टिकोण रनटाइम और स्विज़लिंग पर आधारित है। मैं इस दृष्टिकोण के बारे में 100% निश्चित नहीं हूं, लेकिन आप इसे स्वयं परीक्षण और सुधार सकते हैं।

UIPanGestureRecognizerकोड की सिर्फ एक पंक्ति के साथ किसी भी दिशा निर्धारित करें :

UITableView().panGestureRecognizer.direction = UIPanGestureRecognizer.Direction.vertical

उपयोग pod 'UIPanGestureRecognizerDirection'या कोड:

public extension UIPanGestureRecognizer {

    override open class func initialize() {
        super.initialize()
        guard self === UIPanGestureRecognizer.self else { return }
        func replace(_ method: Selector, with anotherMethod: Selector, for clаss: AnyClass) {
            let original = class_getInstanceMethod(clаss, method)
            let swizzled = class_getInstanceMethod(clаss, anotherMethod)
            switch class_addMethod(clаss, method, method_getImplementation(swizzled), method_getTypeEncoding(swizzled)) {
            case true:
                class_replaceMethod(clаss, anotherMethod, method_getImplementation(original), method_getTypeEncoding(original))
            case false:
                method_exchangeImplementations(original, swizzled)
            }
        }
        let selector1 = #selector(UIPanGestureRecognizer.touchesBegan(_:with:))
        let selector2 = #selector(UIPanGestureRecognizer.swizzling_touchesBegan(_:with:))
        replace(selector1, with: selector2, for: self)
        let selector3 = #selector(UIPanGestureRecognizer.touchesMoved(_:with:))
        let selector4 = #selector(UIPanGestureRecognizer.swizzling_touchesMoved(_:with:))
        replace(selector3, with: selector4, for: self)
    }

    @objc private func swizzling_touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        self.swizzling_touchesBegan(touches, with: event)
        guard direction != nil else { return }
        touchesBegan = true
    }

    @objc private func swizzling_touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        self.swizzling_touchesMoved(touches, with: event)
        guard let direction = direction, touchesBegan == true else { return }
        defer {
            touchesBegan = false
        }
        let forbiddenDirectionsCount = touches
            .flatMap({ ($0.location(in: $0.view) - $0.previousLocation(in: $0.view)).direction })
            .filter({ $0 != direction })
            .count
        if forbiddenDirectionsCount > 0 {
            state = .failed
        }
    }
}

public extension UIPanGestureRecognizer {

    public enum Direction: Int {

        case horizontal = 0
        case vertical
    }

    private struct UIPanGestureRecognizerRuntimeKeys {
        static var directions = "\(#file)+\(#line)"
        static var touchesBegan = "\(#file)+\(#line)"
    }

    public var direction: UIPanGestureRecognizer.Direction? {
        get {
            let object = objc_getAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.directions)
            return object as? UIPanGestureRecognizer.Direction
        }
        set {
            let policy = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
            objc_setAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.directions, newValue, policy)
        }
    }

    fileprivate var touchesBegan: Bool {
        get {
            let object = objc_getAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.touchesBegan)
            return (object as? Bool) ?? false
        }
        set {
            let policy = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
            objc_setAssociatedObject(self, &UIPanGestureRecognizerRuntimeKeys.touchesBegan, newValue, policy)
        }
    }
}

fileprivate extension CGPoint {

    var direction: UIPanGestureRecognizer.Direction? {
        guard self != .zero else { return nil }
        switch fabs(x) > fabs(y) {
        case true:  return .horizontal
        case false: return .vertical
        }
    }

    static func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
        return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
    }
}

0

मैंने यह कोशिश की: जो मेरे लिए सवाल के अनुसार काम करता है

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer is UIPanGestureRecognizer {
        return true
    } else {
        return false
    }
}

0

स्विफ्ट 4.2

मैं आगे गया और एक दिशा बना रहा हूँ पैन जेस्चर:

enum PanDirection {
    case up
    case left
    case right
    case down
}

class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
    
    fileprivate let direction: PanDirection
    
    init(direction: PanDirection, target: AnyObject, action: Selector) {
        self.direction = direction
        super.init(target: target, action: action)
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        
        guard state != .failed else { return }

        let vel = velocity(in: view)

        let velocities: [PanDirection: CGFloat]
            = [.up: -vel.y,
               .left: -vel.x,
               .right: vel.x,
               .down: vel.y]

        let sortedKeys = velocities.sorted { $0.1 < $1.1 }

        if let key = sortedKeys.last?.key,
            key != direction {
            state = .cancelled
        }
    }
}

(प्रयुक्त: https://github.com/fastred/SloppySwiper और https://stackoverflow.com/a/30607392/5790492 )


0

यहाँ स्विफ्ट 5 में एक कस्टम पैन इशारा है

यू इसकी दिशा में बाधा और दिशा में अधिकतम कोण, आप दिशा में इसकी न्यूनतम गति को भी बाधित कर सकते हैं।

enum PanDirection {
    case vertical
    case horizontal
}

struct Constaint {
    let maxAngle: Double
    let minSpeed: CGFloat

    static let `default` = Constaint(maxAngle: 50, minSpeed: 50)
}


class PanDirectionGestureRecognizer: UIPanGestureRecognizer {

    let direction: PanDirection

    let constraint: Constaint


    init(direction orientation: PanDirection, target: AnyObject, action: Selector, constraint limits: Constaint = Constaint.default) {
        direction = orientation
        constraint = limits
        super.init(target: target, action: action)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        let tangent = tan(constraint.maxAngle * Double.pi / 180)
        if state == .began {
            let vel = velocity(in: view)
            switch direction {
            case .horizontal where abs(vel.y)/abs(vel.x) > CGFloat(tangent) || abs(vel.x) < constraint.minSpeed:
                state = .cancelled
            case .vertical where abs(vel.x)/abs(vel.y) > CGFloat(tangent) || abs(vel.y) < constraint.minSpeed:
                state = .cancelled
            default:
                break
            }
        }
    }
}

इस तरह से कॉल करें:

    let pan = PanDirectionGestureRecognizer(direction: .vertical, target: self, action: #selector(self.push(_:)))
    view.addGestureRecognizer(pan)

    @objc func push(_ gesture: UIPanGestureRecognizer){
        if gesture.state == .began{
            // command for once
        }
    }

या

    let pan = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(self.push(_:)), constraint: Constaint(maxAngle: 5, minSpeed: 80))
    view.addGestureRecognizer(pan)

-1

PanGestureRecognizer इंटरफ़ेस में निम्नलिखित परिभाषाएँ हैं:

unsigned int    _canPanHorizontally:1;
unsigned int    _canPanVertically:1;

मैंने इसकी जाँच नहीं की, लेकिन शायद यह उपवर्ग के माध्यम से सुलभ है।


3
होनहार लग रहा है, लेकिन वह एपीआई उजागर नहीं है। निजी APIs का उपयोग आम तौर पर Apple द्वारा अस्वीकृति के रूप में होता है।
विलियम डेनिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.