स्पर्श घटनाओं से निपटने के लिए UIGestureRecognizer ब्लॉक सब-वे


82

मैं यह पता लगाने की कोशिश कर रहा हूं कि यह कैसे सही तरीके से किया जाता है । मैंने स्थिति को चित्रित करने की कोशिश की है: यहाँ छवि विवरण दर्ज करें

मैं एक UITableViewके एक उप के रूप में जोड़ रहा हूँ a UIViewUIViewएक tap- और का जवाब pinchGestureRecognizerहै, लेकिन जब ऐसा करने से, tableview उन दो इशारों पर प्रतिक्रिया बंद हो जाता है (यह अभी भी स्वाइप के प्रति प्रतिक्रिया करता)।

मैंने इसे निम्नलिखित कोड के साथ काम किया है, लेकिन यह स्पष्ट रूप से एक अच्छा समाधान नहीं है और मुझे यकीन है कि एक बेहतर तरीका है। इसे UIView(पर्यवेक्षण में) डाला जाता है :

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if([super hitTest:point withEvent:event] == self) {
        for (id gesture in self.gestureRecognizers) {
            [gesture setEnabled:YES];
        }
        return self;
    }
    for (id gesture in self.gestureRecognizers) {
        [gesture setEnabled:NO];
    }
    return [self.subviews lastObject];
}

जवाबों:


182

मुझे एक समान समस्या थी और इस एसओ प्रश्न में मेरा समाधान मिला । सारांश में, अपने आप को अपने प्रतिनिधि के रूप में सेट करें UIGestureRecognizerऔर फिर अपने पहचानकर्ता को स्पर्श को संसाधित करने की अनुमति देने से पहले लक्षित दृश्य की जांच करें। प्रासंगिक प्रतिनिधि विधि है:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch

3
मुझे यह समाधान सबसे अधिक पसंद है क्योंकि इसमें छुआछूत के साथ खिलवाड़ नहीं है, hitTest:withEvent:या pointInside:withEvent:
DarkDust

6
स्वच्छ समाधान, जैसे return !(touch.view == givenView);कि आप उदाहरण के साथ परीक्षण कर सकते हैं यदि आप किसी दिए गए दृश्य को बाहर करना चाहते हैं या return !(touch.view.tag == kTagNumReservedForExcludingViews);जब आप अपने पहचानकर्ता को अलग-अलग साक्षात्कारों के पूरे समूह पर स्पर्श को संसाधित करने से रोकना चाहते हैं।
दिनांक

6
मैं हिट टेस्ट के साथ करूंगा - (BOOL)isDescendantOfView:(UIView *)view- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)eventUIGestureRecognizer को उप-वर्ग करते समय यह भी ठीक काम करता है ।
क्रिस्टोफ़

1
@ जस्टिन, क्या होगा अगर हमारा जेस्चर पहचानकर्ता पहचान से संबंधित है और हम जेस्चर पहचानकर्ताओं को सौंपने में असमर्थ हैं?
गोखन बारिस अकर

108

टच इवेंट्स को सबव्यू के लिए ब्लॉक करना डिफ़ॉल्ट व्यवहार है। आप इस व्यवहार को बदल सकते हैं:

UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];

5
यह स्पर्श घटनाओं को उप-साक्षात्कारों में भेजेगा, लेकिन यह इशारा पहचानकर्ता को भी भेजा जाएगा। तो यह साक्षात्कारों को अवरुद्ध करने से रोकेगा लेकिन हावभाव पहचानकर्ता को अभी भी साक्षात्कारों में मान्यता दी जाएगी।
जोनाथन।

@Jonathan। हाँ, मैं आपसे सहमत हूँ। मैंने अपने जेस्चर हैंडलर विधि में क्या किया है, यह जांच लें कि क्या जेस्चर का स्थान संबंधित सबव्यू के अंदर होता है जिस स्थिति में मुझे शेष कोड को निष्पादित करने की आवश्यकता नहीं है। इसके अलावा, एक कारण मैंने इस समाधान को चुना है कि UITapGestureRecognizer translationInViewविधि घोषित नहीं करता है । इसलिए ऊपर उल्लिखित UIGestureRecognizerDelegate पद्धति को लागू करने से केवल त्रुटि के साथ दुर्घटना होगी ... unrecognized selector sent to blah। जाँच करने के लिए, की तरह कुछ का उपयोग करें: CGRectContainsPoint(subview.bounds, [recognizer locationInView:subview])
MkVal

ओपी के प्रश्न के अनुसार, इस उत्तर को मुख्य उत्तर के रूप में चुना जाना चाहिए।
farzadshbfn 13

5

मैं एक ड्रॉपडाउन सबव्यू प्रदर्शित कर रहा था जिसका अपना एक टेबलव्यू था। नतीजतन, touch.viewकभी-कभी कक्षाओं की तरह वापसी करेगा UITableViewCell। मुझे यह सुनिश्चित करने के लिए सुपरक्लास (तों) के माध्यम से कदम बढ़ाना था कि मुझे लगा कि यह उपवर्ग था।

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    UIView *view = touch.view;
    while (view.class != UIView.class) {
        // Check if superclass is of type dropdown
        if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own
            NSLog(@"Is of type dropdown; returning NO");
            return NO;
        } else {
            view = view.superview;
        }
    }

    return YES;
}

उस समय के लिए लूप का खाता है
20-28 में joslinm

5

@Pin Shih वांग जवाब पर बिल्डिंग । हम टैप जेस्चर पहचानकर्ता वाले दृश्य के अलावा अन्य सभी टैपों को अनदेखा करते हैं। सभी टैप दृश्य पदानुक्रम के लिए सामान्य हैं, जैसा कि हमने सेट किया है tapGestureRecognizer.cancelsTouchesInView = false। यहाँ Swift3 / 4 में कोड है:

func ensureBackgroundTapDismissesKeyboard() {
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    tapGestureRecognizer.cancelsTouchesInView = false
    self.view.addGestureRecognizer(tapGestureRecognizer)
}

@objc func handleTap(recognizer: UIGestureRecognizer) {
    let location = recognizer.location(in: self.view)
    let hitTestView = self.view.hitTest(location, with: UIEvent())
    if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) {
        // I dismiss the keyboard on a tap on the scroll view
        // REPLACE with own logic
        self.view.endEditing(true)
    }
}

मैं जेस्चर पहचानकर्ता की तुलना ए से कैसे कर सकता हूं UISwipeActionStandardButton? मैंने कोशिश की.some(UISwipeActionStandardButton)
जलील

4

एक संभावना यह है कि आपके जेस्चर पहचानकर्ता (यदि आप पहले से ही नहीं हैं) को हटा दें और -touchesBegan:withEvent:इस तरह से ओवरराइड करें कि यह निर्धारित करता है कि क्या प्रत्येक टच एक बहिष्कृत सबव्यू में शुरू हुआ था और -ignoreTouch:forEvent:यदि ऐसा हुआ तो उस टच के लिए कॉल करता है ।

जाहिर है, आपको बहिष्कृत साक्षात्कार का ट्रैक रखने के लिए एक संपत्ति जोड़ने की आवश्यकता होगी, या शायद बेहतर, बहिष्कृत साक्षात्कारों की एक सरणी।


वहाँ कोड के ढेर है यहाँ github.com/-
johndpope

2

किसी भी वर्ग के वारिस के बिना करना संभव है।

आप जेस्चर के कॉलबैक चयनकर्ता में जेस्चर की पहचान कर सकते हैं

यदि view.gestureRecognizers में आपका जेस्चर नहीं है, तो पहचानें, इसे अनदेखा करें

उदाहरण के लिए

- (void)viewDidLoad
{
    UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self     action:@selector(handleSingleTap:)];
    singleTapGesture.numberOfTapsRequired = 1;
}

यहाँ view.gestureRecognizers जाँच करें

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
    UIEvent *event = [[UIEvent alloc] init];
    CGPoint location = [gestureRecognizer locationInView:self.view];

    //check actually view you hit via hitTest
    UIView *view = [self.view hitTest:location withEvent:event];

    if ([view.gestureRecognizers containsObject:gestureRecognizer]) {
        //your UIView
        //do something
    }
    else {
        //your UITableView or some thing else...
        //ignore
    }
}

जैसा कि अन्य उत्तरों में उल्लेख किया गया है, यदि इस पद्धति का उपयोग करना सुनिश्चित करें कि टैप जेस्चर पहचानकर्ता आपके दृश्य के साथ टैप को आगे की ओर बढ़ाता है: ऊपर singleTapGesture.cancelsTouchesInView = NO;जोड़ा गयाviewDidLoad
Nick Ager

1

मैंने एक UIGestureRecognizer उपवर्ग का निर्माण किया जो एक विशिष्ट दृश्य के पर्यवेक्षकों से जुड़े सभी हावभाव पहचानकर्ताओं को अवरुद्ध करने के लिए डिज़ाइन किया गया है।

यह मेरे WEPopover प्रोजेक्ट का हिस्सा है। आप इसे यहाँ पा सकते हैं ।


1

पेरेंटव्यू के सभी पहचानकर्ताओं के लिए एक प्रतिनिधि को लागू करें और पहचान पत्र में जेस्चर रिकॉग्निज़र विधि डालें जो एक साथ पहचानकर्ताओं को ट्रिगर करने के लिए ज़िम्मेदार हो:

func gestureRecognizer(UIGestureRecognizer,       shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool {
if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) {
    return true
    } else {
    return false
}

}

यू फेल के तरीकों का इस्तेमाल कर सकते हैं, अगर आप बच्चों को ट्रिगर बनाना चाहते हैं, लेकिन अभिभावकों को नहीं:

https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate


0

मैं एक पॉपओवर भी कर रहा था और यह मैंने कैसे किया

func didTap(sender: UITapGestureRecognizer) {

    let tapLocation = sender.locationInView(tableView)

    if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
        sender.cancelsTouchesInView = false
    }
    else {
        delegate?.menuDimissed()
    }
}

0

आप इसे बंद और चालू कर सकते हैं .... मेरे कोड में मैंने कुछ ऐसा किया जैसे कि जब कीबोर्ड दिखाई नहीं दे रहा था, तो मैं इसे बंद करना चाहता था, आप इसे अपनी स्थिति में लागू कर सकते हैं:

यह कॉल दृश्यदर्शी आदि है:

NSNotificationCenter    *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];

फिर दो तरीके बनाएँ:

-(void) notifyShowKeyboard:(NSNotification *)inNotification 
{
    tap.enabled=true;  // turn the gesture on
}

-(void) notifyHideKeyboard:(NSNotification *)inNotification 
{
    tap.enabled=false;  //turn the gesture off so it wont consume the touch event
}

यह क्या करता है नल को निष्क्रिय करता है। मुझे टैप को एक इंस्टेंस वेरिएबल में बदलना था और इसे डीललोक में जारी करना था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.