UIButGestureRecognizer वाले दृश्य के अंदर UIButton


184

मेरे पास एक के साथ दृश्य है UITapGestureRecognizer । इसलिए जब मैं दृश्य पर टैप करता हूं तो इस दृश्य के ऊपर एक और दृश्य दिखाई देता है। इस नए दृश्य में तीन बटन हैं। जब मैं अब इनमें से किसी एक बटन पर प्रेस करता हूं तो मुझे बटन कार्रवाई नहीं मिलती है, मुझे केवल टैप जेस्चर कार्रवाई मिलती है। इसलिए मैं इन बटनों का उपयोग नहीं कर पा रहा हूं। मैं इन बटन के माध्यम से घटनाओं को प्राप्त करने के लिए क्या कर सकता हूं? अजीब बात यह है कि बटन अभी भी हाइलाइट किए गए हैं।

मेरे द्वारा टैप किए जाने के बाद मैं केवल UITapGestureRecognizer को नहीं निकाल सकता। क्योंकि इसके साथ ही नया दृश्य भी हटाया जा सकता है। इसका मतलब है कि मैं फुलस्क्रीन वीडियो कंट्रोल जैसा व्यवहार चाहता हूं ।

जवाबों:


256

आप अपने नियंत्रक या दृश्य (जो भी पहचानकर्ता बनाता है) के प्रतिनिधि के रूप में सेट कर सकते हैं UITapGestureRecognizer। फिर प्रतिनिधि में आप लागू कर सकते हैं -gestureRecognizer:shouldReceiveTouch:। आपके कार्यान्वयन में आप परीक्षण कर सकते हैं कि क्या स्पर्श आपके नए सबव्यू से संबंधित है, और यदि ऐसा होता है, तो इशारे पहचानकर्ता को इसे अनदेखा करने का निर्देश दें। कुछ इस प्रकार है:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // test if our control subview is on-screen
    if (self.controlSubview.superview != nil) {
        if ([touch.view isDescendantOfView:self.controlSubview]) {
            // we touched our control surface
            return NO; // ignore the touch
        }
    }
    return YES; // handle the touch
}

मेरी हेडर फ़ाइल में, मेरे पास UIGestoreRegognizerDelegate को लागू करने का मेरा विचार था, और मेरे .mi में आपके कोड को ऊपर जोड़ा गया था। नल कभी भी इस विधि में प्रवेश नहीं करता है, यह सीधे मेरे हैंडलर के पास जाता है। कोई विचार?
kmehta

1
@kmehta आप सबसे अधिक संभावना UIGestureRecognizer प्रतिनिधि संपत्ति सेट करना भूल गए।
तक

क्या यह उत्तर उन सभी मामलों को संभालने के लिए सामान्यीकृत किया जा सकता है जहां एक IBAction शामिल है?
मार्टिन विकमन

@Martin आईबीए संकलन voidका पता लगाने के लिए उपयोग करने के लिए रनटाइम के पीछे किसी भी जानकारी को नहीं छोड़ता है, इसलिए इसे संकलित करता है। लेकिन आप क्या कर सकते हैं पदानुक्रम को देखने के लिए चलना, परीक्षण करना UIControlऔर NOयदि आपको कोई नियंत्रण मिले तो वापस लौटना ।
लिली बॉलर

इसके लिए thx, यह मेरी मदद करता है। यदि आपका बटन UIImageView में है, तो सुनिश्चित करें कि userInteractionEnabled of imageView हां में सेट है।
james075

156

केसी बॉलार्ड के जवाब तक केसी के अनुसरण के रूप में:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
        if ([touch.view isKindOfClass:[UIControl class]]) {
            // we touched a button, slider, or other UIControl
            return NO; // ignore the touch
        }
    return YES; // handle the touch
}

यह मूल रूप से बटन, स्लाइडर्स आदि जैसे सभी उपयोगकर्ता इनपुट प्रकारों को नियंत्रित करता है


1
यह एक लचीला समाधान है जो setCancelsTouchesInView = NOनियंत्रण के साथ बातचीत पर टैप जेस्चर को ट्रिगर नहीं करने के साथ हो सकता है । हालाँकि आप इसे बेहतर तरीके से लिख सकते हैं:return ![touch.view isKindOfClass:[UIControl class]];
griga13

स्विफ्ट 4+ सॉल्यूशन: रिटर्न! (टच.व्यू यूआईसीट्रॉल है)
नेटीसलर

103

यह उत्तर यहां मिला: लिंक

आप भी उपयोग कर सकते हैं

tapRecognizer.cancelsTouchesInView = NO;

जो सभी नल को पकड़ने के लिए केवल एक ही नल पहचानकर्ता को रोकता है

अद्यतन - माइकल ने इस संपत्ति का वर्णन करने वाले दस्तावेज़ के लिंक का उल्लेख किया है: cancelsTouchesInView


8
यह स्वीकृत उत्तर IMO होना चाहिए। यह हर सबव्यू को टैप को अपने आप से हैंडल करने देता है और उस व्यू को रोकता है, जिसमें टैप को 'हाईजैकिंग' से जोड़ा गया है। एक प्रतिनिधि को लागू करने की आवश्यकता नहीं है अगर आप सभी करना चाहते हैं, तो एक दृश्य क्लिक करने योग्य है (पहले उत्तरदाता से इस्तीफा देने के लिए / टेक्स्टफिल्ड आदि पर कीबोर्ड छिपाने के लिए) .. भयानक!
ईके

4
यह निश्चित रूप से स्वीकृत उत्तर होना चाहिए। इस उत्तर ने मुझे Apple प्रलेखन को ठीक से पढ़ने के लिए प्रेरित किया , जिससे यह स्पष्ट हो जाता है कि जेस्चर पहचानकर्ता, जब तक आप ऐसा नहीं करते हैं, तब तक वे इनवॉइस को पहचानने से रोक सकते हैं।
माइकल वान डेर वेस्टहुइज़न

1
यह काम करता था, लेकिन अब यह मेरे लिए काम नहीं कर रहा है..शायद क्योंकि मेरे पास बटन के नीचे एक स्क्रॉल दृश्य है? मुझे ऊपर के उत्तरों की तरह प्रतिनिधि को लागू करना था।
xissburg

7
थोड़ा प्रयोग करने के बाद, मैंने देखा कि यह केवल तभी काम करेगा जब जिस दृश्य में जेस्चर पहचानकर्ता होता है वह UIControl का एक सहोदर है, और यह नहीं होगा यदि दृश्य UIControl का जनक है।
एक्सिसबर्ग

6
वास्तव में इरादा के रूप में काम नहीं करते ... हाँ, यह टैप पहचानकर्ता को UIControl पर ईवेंट को खाने से रोक रहा है। लेकिन यह अभी भी पहचानकर्ता कार्रवाई चला रहा है, जो एक ही समय में 2 कार्रवाई चला रहा है।
टेक यिन

71

केविन बालार्ड के जवाब के अनुवर्ती के रूप में, मुझे यही समस्या थी और इस कोड का उपयोग करके समाप्त हुई:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isKindOfClass:[UIButton class]]){
        return NO;
    }
    return YES;
}

इसका एक ही प्रभाव है, लेकिन यह किसी भी दृश्य गहराई पर किसी भी UIButton पर काम करेगा (मेरा UIButton कई दृश्य गहरा था और UIGestureRecognizer के प्रतिनिधि के पास इसका संदर्भ नहीं था।)


6
यहाँ एक डिक मत बनो, लेकिन यह वास्तव में हाँ और नहीं है। कृपया कोको सम्मेलनों का उपयोग करें। TRUE / FALSE / NULL CoreFoundation-Layer के लिए है।
२०:११

मैंने जो पढ़ा है, उससे वास्तव में पठनीयता के लिए हाँ और नहीं बनाया गया था। पठनीयता व्यक्तिपरक है। यह विधि और संपत्ति के नामकरण परंपराओं से उपजा है जिसके बारे में हर कोई चिंतित नहीं है। यदि आप नामकरण सम्मेलन का कड़ाई से पालन करना चाहते हैं, तो हाँ किसी भी NSWhatever के लिए YES और NO का उपयोग करें। हालाँकि, मैं कहूंगा कि यदि आप डेवलपर्स का सर्वेक्षण करते हैं, तो आपको मिश्रित राय मिलेगी, जिसमें से इनमें से एक अधिक पठनीय है [बटन setHidden: YES]; -या- [बटन सेट किया गया: TRUE];
दलाल जूस मैकजोंस

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

2
यह व्यक्तिपरक लग सकता है, लेकिन कोको प्रोग्रामिंग की थोड़ी देर के बाद आप वास्तव में कोड के अधिक अर्थपूर्ण प्रवाह में आ जाते हैं ... "TRUE" सिर्फ वस्तुनिष्ठ-सी के वर्षों के बाद अब वास्तव में गलत लगता है, क्योंकि यह "छिपे हुए" से बहुत मेल नहीं खाता है कुंआ।
केंडल हेल्मसटेटर गेलनर

कब से आप यूआईटच इवेंट के अंदर टच अप इनसाइड यूआईटच इवेंट (बाद में यूआईब्यूटन टैप करके उत्पन्न होने वाली घटना) के रूप में एक यूआईब्यूटन के लिए टैप इशारे कर सकते हैं? यह एक बटन के लिए टैप जेस्चर पहचानकर्ता बनाने के लिए डुप्लिकेट और गलत लगता है जिसमें 15 टच इवेंट पहले से ही एक टैप जेस्चर के साथ जुड़े हुए हैं। मैं कोड देखना चाहता हूं, अनुमान नहीं।
बुश पर जेम्स बुश

10

IOS 6.0 और बाद में, डिफ़ॉल्ट नियंत्रण क्रियाएं जेस्चर पहचानकर्ता के अतिव्यापी व्यवहार को रोकती हैं। उदाहरण के लिए, बटन के लिए डिफ़ॉल्ट क्रिया एक टैप है। यदि आपके पास बटन के माता-पिता के दृश्य से जुड़ा एक एकल नल जेस्चर पहचानकर्ता है, और उपयोगकर्ता बटन टैप करता है, तो बटन की कार्रवाई विधि इशारा पहचानकर्ता के बजाय स्पर्श घटना प्राप्त करती है। यह केवल इशारा पहचान पर लागू होता है जो नियंत्रण के लिए डिफ़ॉल्ट कार्रवाई को ओवरलैप करता है, जिसमें शामिल हैं: .....

Apple के एपीआई डॉक्स से


8

ये उत्तर अधूरे थे। मुझे इस बूलियन ऑपरेशन का उपयोग करने के तरीके के रूप में कई पोस्ट पढ़ना था।

अपनी .h फ़ाइल में इसे जोड़ें

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

आपकी * .m फ़ाइल में यह जोड़ें

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

    NSLog(@"went here ...");

    if ([touch.view isKindOfClass:[UIControl class]])
    {
        // we touched a button, slider, or other UIControl
        return NO; // ignore the touch
    }
    return YES; // handle the touch
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.



    //tap gestrure
    UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)];
    [tapGestRecog setNumberOfTapsRequired:1];
    [self.view addGestureRecognizer:tapGestRecog];


// This line is very important. if You don't add it then your boolean operation will never get called
tapGestRecog.delegate = self;

}


-(IBAction) screenTappedOnce
{
    NSLog(@"screenTappedOnce ...");

}

7

इसे यहाँ से करने का एक और तरीका मिला । यह प्रत्येक बटन के अंदर स्पर्श का पता लगाता है या नहीं।

(1) पॉइंट इनसाइड: withEvent: (2) स्थान

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
       shouldReceiveTouch:(UITouch *)touch {
    // Don't recognize taps in the buttons
    return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] &&
            ![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] &&
            ![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]);
}

मैंने इसके लिए अन्य सभी समाधानों की कोशिश की, लेकिन -point -Inside: withEvent: approach केवल एक ही था जिसने मेरे लिए काम किया।
केनी वायलैंड


3

स्विफ्ट 5

परिचारिका के साथ बटन पर बटन

 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if let _ = touch.view as? UIButton { return false }
    return true
}

मेरे मामले में हिटटेस्ट लागू करना मेरे लिए काम कर गया। मेरे पास बटन के साथ संग्रह दृश्य था

यह विधि यह point(inside:with:)निर्धारित करने के लिए कि किस सबव्यू को एक टच ईवेंट प्राप्त करना चाहिए, प्रत्येक सबव्यू की विधि को कॉल करके व्यू पदानुक्रम का पता लगाता है। यदि यह point(inside:with:)सच है, तो सबव्यू का पदानुक्रम इसी तरह से निर्धारित होता है जब तक कि सामने वाला दृश्य निर्दिष्ट बिंदु नहीं पाया जाता है।

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard isUserInteractionEnabled else { return nil }

    guard !isHidden else { return nil }

    guard alpha >= 0.01 else { return nil }

    guard self.point(inside: point, with: event) else { return nil }

    for eachImageCell in collectionView.visibleCells {
        for eachImageButton in eachImageCell.subviews {
            if let crossButton = eachImageButton as? UIButton {
                if crossButton.point(inside: convert(point, to: crossButton), with: event) {
                    return crossButton
                }
            }
        }
    }
    return super.hitTest(point, with: event)
}

1

आप निम्नलिखित बूलियन सेट करके UITapGestureRecognizer को अन्य घटनाओं (जैसे कि आपके बटन पर टैप) को रद्द करने से रोक सकते हैं:

    [tapRecognizer setCancelsTouchesInView:NO];

1

यदि आपका परिदृश्य इस प्रकार है:

आपके पास एक सरल दृश्य है और कुछ UIButtons, UITextField नियंत्रणों को उस दृश्य के साक्षात्कार के रूप में जोड़ा गया है। अब आप कीबोर्ड को खारिज करना चाहते हैं जब आप नियंत्रण को छोड़कर दृश्य पर कहीं और स्पर्श करते हैं (आपके द्वारा जोड़े गए साक्षात्कार)

तब समाधान है:

निम्नलिखित विधि को अपने XYZViewController.m में जोड़ें (जिसमें आपका विचार है)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

पहले मैंने @cdasher के उत्तर के साथ कोशिश की, लेकिन मेरे मामले में भी बटन पर क्लिक करने पर, Iam ने टचकॉउन को व्यूकंट्रोलर में मेरे "दृश्य" के रूप में देखा, लेकिन मेरे "यूब्यूटॉन" नियंत्रण के रूप में नहीं। क्या कोई कह सकता है कि टच की व्यू प्रॉपर्टी उस मूल दृश्य को क्यों नहीं लौटा रही है जिसमें टैप हुआ है
नवीन रघुवीर

1
यदि आपके पास स्क्रॉलव्यू या कुछ अन्य दृश्य हैं जो स्पर्श घटनाओं का दावा करते हैं तो काम नहीं करेगा।
लकराइडर

1

सीडीशर के उत्तर का अनुकूलन, आपको मिलता है

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch 
{
    return ![touch.view isKindOfClass:[UIControl class]];
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.