UITapGestureRecognizer UITableView didSelectRowAtIndexPath को तोड़ता है


207

मैंने टेक्स्ट फ़ील्ड को स्क्रॉल करने के लिए अपना स्वयं का फ़ंक्शन लिखा है जब कीबोर्ड दिखाता है। टेक्स्ट फ़ील्ड से दूर टैप करके कीबोर्ड को खारिज करने के लिए, मैंने एक ऐसा बनाया है UITapGestureRecognizerजो टैप करते समय टेक्स्ट फ़ील्ड पर पहले रिस्पॉन्डर को इस्तीफा देने का ख्याल रखता है।

अब मैंने टेक्स्टफ़ील्ड के लिए एक स्वत: पूर्णता भी बनाई है जो UITableViewटेक्स्ट फ़ील्ड के ठीक नीचे बनाता है और इसे आइटम के साथ पॉप्युलेट करता है जैसे कि यूजर एंट्रेस टेक्स्ट।

हालांकि, ऑटो पूर्ण तालिका में प्रविष्टियों में से एक का चयन करते समय, didSelectRowAtIndexPathकॉल नहीं किया जाता है। इसके बजाय, ऐसा लगता है कि टैप जेस्चर पहचानकर्ता को बुलाया जा रहा है और बस पहले उत्तरदाता को इस्तीफा देता है।

मैं अनुमान लगा रहा हूं कि टैप मैसेज को नीचे रखने के लिए टैप जेस्चर पहचानकर्ता को बताने का कोई तरीका है UITableView, लेकिन मैं यह पता नहीं लगा सकता कि वह क्या है। किसी भी मदद को बहुत सराहा जाएगा।


जवाबों:


258

ठीक है, अंत में इशारे पहचानकर्ता डॉक्स के माध्यम से कुछ खोज के बाद यह पाया।

समाधान UIGestureRecognizerDelegateनिम्नलिखित को लागू करने और जोड़ने का था:

////////////////////////////////////////////////////////////
// UIGestureRecognizerDelegate methods

#pragma mark UIGestureRecognizerDelegate methods

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isDescendantOfView:autocompleteTableView]) {

        // Don't let selections of auto-complete entries fire the 
        // gesture recognizer
        return NO;
    }

    return YES;
}

इसका ख्याल रखा। उम्मीद है कि इससे दूसरों को भी मदद मिलेगी।


आपको पाठ क्षेत्र पर टैप को भी छोड़ना होगा।
स्टीवन क्रेमर

5
मेरे पास अधिक भाग्य थाreturn ![touch.view isKindOfClass:[UITableViewCell class]];
जोश पैराडायर

1
@Josh यह काम नहीं करता है यदि आप सेल के अंदर लेबल पर टैप करते हैं। वास्तव में जेसन का जवाब मेरी जरूरत के लिए एकदम सही है।
विलियम टी।

लेकिन यह आपकी समस्या का जवाब नहीं है हालांकि, नहीं? यह या तो / या है। मूल रूप से टेबल व्यू पर कोई भी स्पर्श इशारा पहचानकर्ता के साथ महत्वहीन है .... जो आप चाहते हैं वह है जेस्चर इशारा और काम करने के लिए टेबल व्यू का चयन
पोस्टकोडिज़्म

5
@Durgaprasad करने के लिए अक्षम इशारा पहचानकर्ता स्पष्ट रूप से जब कोशिकाओं का चयन मैं एक जोड़ा ![touch.view isEqual: self.tableView] &&से पहले [touch.view isDescendantOfView: self.tableView]बाहर करने के लिए tableViewखुद को (क्योंकि isDescendantOfView:यह भी रिटर्न YESअगर तर्क-व्यू रिसीवर-व्यू में ही है)। आशा है कि अन्य लोगों की मदद करता है जो एक ही परिणाम चाहते हैं।
anneblue

220

इस समस्या को हल करने का सबसे आसान तरीका है:

UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] 
    initWithTarget:self action:@selector(tap:)];
[tapRec setCancelsTouchesInView:NO];

यह UIGestureRecognizerनल को पहचानने देता है और अगले उत्तरदाता को स्पर्श भी देता है । इस पद्धति का एक अनपेक्षित परिणाम है यदि आपके पास एक UITableViewCellऑन-स्क्रीन है जो किसी अन्य दृश्य नियंत्रक को धक्का देता है। यदि उपयोगकर्ता कीबोर्ड को खारिज करने के लिए पंक्ति को टैप करता है, तो कीबोर्ड और पुश दोनों को पहचाना जाएगा। मुझे संदेह है कि यह वही है जो आप चाहते हैं, लेकिन यह विधि कई स्थितियों के लिए पर्याप्त है।

इसके अलावा, रॉबर्ट के उत्तर पर विस्तार करते हुए, यदि आपके पास प्रश्न में तालिका के लिए एक संकेतक है, तो आप सीधे स्ट्रिंग में परिवर्तित होने के बजाय इसकी कक्षा की तुलना कर सकते हैं और आशा करते हैं कि Apple नामकरण नहीं बदलता है:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
     shouldReceiveTouch:(UITouch *)touch
{
    if([touch.view class] == tableview.class){
        return //YES/NO
    }

    return //YES/NO

}

याद रखें, आपको UIGestureRecognizerइस कोड के साथ एक प्रतिनिधि होने की भी घोषणा करनी होगी ।


4
धन्यवाद, setCancelsTouchesInView सब कुछ बदलता है :)
पोस्टकोडिज़्म

हो सकता है isDescendantOfViewकि अगर classआप बराबर हैं, तब भी चेक करने की बजाय इसका उपयोग करना चाहते हैं । आप की जरूरत पर निर्भर करता है
शिम

71

cancelsTouchesInViewअसत्य के लिए अपने पहचानकर्ता का सेट । अन्यथा, यह अपने लिए स्पर्श का "उपभोग" करता है, और इसे तालिका दृश्य पर पारित नहीं करता है। इसलिए चयन घटना कभी नहीं होती है।

उदाहरण के लिए swift

let tapOnScreen: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "CheckTheTime")
tapOnScreen.cancelsTouchesInView = false
view.addGestureRecognizer(tapOnScreen)

1
इसके लिए थैंक्स अलॉट!
बिशन

1
स्विफ्ट में यह सबसे साफ है। धन्यवाद
Dx_

मेज़पोश, सुंदर और सरल में कोशिकाओं के भीतर अच्छी तरह से काम करता है!
अबदोलेरहमान

@ लोयूर बहुत सही
bLacK hoLE

अभी भी नल इशारे के बजाय सेल क्लिक करें
famfamfam

42

और स्विफ्ट के लिए (@ जेसन से जवाब पर आधारित):

class MyAwesomeClass: UIViewController, UIGestureRecognizerDelegate

private var tap: UITapGestureRecognizer!

override func viewDidLoad() {
   super.viewDidLoad()

   self.tap = UITapGestureRecognizer(target: self, action: "viewTapped:")
   self.tap.delegate = self
   self.view.addGestureRecognizer(self.tap)
}

// UIGestureRecognizerDelegate method
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if touch.view?.isDescendantOfView(self.tableView) == true {
        return false
    }
    return true
}

थैंक्स बहुत कुछ इसने मेरा समय बचाया।
बिशन

22

मेरे पास एक टेबल व्यू पर एक टैप जेस्चर जोड़ने के लिए एक बेहतर समाधान हो सकता है लेकिन एक ही समय में सेल चयन की अनुमति दे सकता है:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if gestureRecognizer is UITapGestureRecognizer {
        let location = touch.locationInView(tableView)
        return (tableView.indexPathForRowAtPoint(location) == nil)
    }
    return true
}

मैं सिर्फ स्क्रीन के बिंदु पर एक सेल की तलाश करता हूं जहां उपयोगकर्ता टैप कर रहा है। यदि कोई अनुक्रमणिका पथ नहीं मिला है, तो मैं इशारे को स्पर्श प्राप्त करने देता हूं अन्यथा मैं इसे रद्द कर देता हूं। मेरे लिए यह बहुत अच्छा काम करता है।


1
यह समाधान चट्टानों! तालिका के खाली क्षेत्र से सेल को अलग करने के लिए बहुत उपयोगी है ..
एलेसेंड्रो ऑर्नानो

18

मुझे लगता है कि कोड्स के ब्लॉक लिखने की कोई जरूरत नहीं है, बस अपने जेस्चर ऑब्जेक्ट के लिए सेट cancelsTouchesInViewकरें false, डिफ़ॉल्ट रूप से trueऔर आपको बस इसे सेट करना है false। यदि आप UITapGestureअपने कोड में ऑब्जेक्ट का उपयोग कर रहे हैं और UIScrollView(टेबलव्यू, कलेक्शनव्यू) का भी उपयोग कर रहे हैं तो इस प्रॉपर्टी को सेट करेंfalse

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)

इस उत्तर को पोस्ट करने के लिए धन्यवाद
Gustavo Baiocchi Costa

14

एक समान समाधान यह gestureRecognizer:shouldReceiveTouch:देखने के लिए कि क्या कार्रवाई करनी है, यह निर्धारित करने के लिए दृश्य वर्ग का उपयोग करना है। इस दृष्टिकोण का लाभ तालिका के आसपास के क्षेत्र में सीधे नल नहीं है (ये क्षेत्र के विचार अभी भी यूआईटेबल व्यू इंस्टेंस से उतरते हैं, लेकिन वे कोशिकाओं का प्रतिनिधित्व नहीं करते हैं)।

यह भी एक बोनस है कि यह एक दृश्य पर कई तालिकाओं के साथ काम करता है (अतिरिक्त कोड को जोड़े बिना)।

कैविएट: एक धारणा है कि Apple क्लासनेम नहीं बदलेगा।

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return ![NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"];
}

1
वर्ग नाम की स्ट्रिंग को खत्म करने के लिए, इस लाइन का उपयोग करेंreturn ![[touch.view.superview class] isSubclassOfClass:[UITableViewCell class]];
Nianliang

7

के लिए स्विफ्ट 4.2 समाधान लागू करने के लिए था UIGestureRecognizerDelegateऔर निम्नलिखित जोड़ें:

extension ViewController : UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view!.isDescendant(of: tblView) {
            return false
        }
        return true
    }
}

जब आप तालिका दृश्य पर क्लिक करते हैं तो यह प्रतिनिधि विधि गलत हो जाती है और didSelectRowAtIndexPathतालिका दृश्य की विधि ठीक से काम करती है।


1
इस उत्तर को पोस्ट करने के लिए धन्यवाद दोस्त, आप मेरा समय बचाते हैं।
जय भलानी

4

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

परिणामी कोड अब्दुलरहमान मसऊद के उत्तर और निकोलज नीलसन के उत्तर का एक संयोजन है।

extension MyViewController: UIGestureRecognizerDelegate {
    func addGestureRecognizer() {
        let tapOnScreen = UITapGestureRecognizer(target: self,
                                                action: #selector(functionToCallWhenUserTapsOutsideOfTableView))

        // stop the gesture recognizer from "consuming" the touch event, 
        // so that the touch event can reach other buttons on view.
        tapOnScreen.cancelsTouchesInView = false

        tapOnScreen.delegate = self

        self.view.addGestureRecognizer(tapOnScreen)
    }

    // if your tap event is on the menu, don't run the touch event.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view?.isDescendant(of: self.tableView) == true {
            return false
        }
        return true
    }

    @objc func functionToCallWhenUserTapsOutsideOfTableView() {

        print("user tapped outside table view")
    }
}

और MyViewControllerकक्षा में, जिस कक्षा में UITableView, में onViewDidLoad(), मैंने कॉल करना सुनिश्चित किया addGestureRecognizer():

class MyViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        self.addGestureRecognizer()
        ...
    }
    ...
}

3

बस सेट cancels touches in viewकरने के लिए falseनीचे किसी भी इशारा के लिए (table/collection)View:

- इंटरफ़ेस बिल्डर

Interfacebuilder

- कोड

<#gestureRecognizer#>.cancelsTouchesInView = false

क्या होगा अगर मैं इसे अक्षम करना चाहता हूं तो यह न केवल काम करता है, बल्कि इसके साथ काम करने की अनुमति नहीं देता है?
आईड शॉक्री

1

हालांकि यह देर हो चुकी है और बहुत से लोग पाते हैं कि उपरोक्त सुझाव ठीक काम करते हैं, मुझे जेसन या टीमिलिगन के तरीके काम करने के लिए नहीं मिल सके।

मेरे पास Static tableView है जिसमें कई सेल हैं जिनमें TextFields हैं जो केवल नंबर कीबोर्ड का उपयोग करके नंबर इनपुट प्राप्त करते हैं। यह मेरे लिए आदर्श था:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if(![touch.view isKindOfClass:[UITableViewCell class]]){

        [self.firstTF resignFirstResponder];
        [self.secondTF resignFirstResponder];
        [self.thirdTF resignFirstResponder];
        [self.fourthTF resignFirstResponder];

        NSLog(@"Touches Work ");

        return NO;
    }
    return YES;
}

सुनिश्चित करें कि आपने इसे <UIGestureRecognizerDelegate>अपनी .h फ़ाइल में लागू किया है।

यह पंक्ति ![touch.view isKindOfClass:[UITableViewCell class]]जांचती है कि क्या टेबल व्यूसेल का टैप किया गया था और किसी भी सक्रिय कीबोर्ड को खारिज कर दिया गया था।


1

साधारण समाधान स्पर्श पाने के लिए UITableViewCell में UIControl उदाहरणों का उपयोग कर रहा है। नल पाने के लिए आप किसी भी विचार को userInteractionEnables == NO के साथ UIControl में जोड़ सकते हैं।


0

यहाँ मेरा समाधान है, जो पहचानकर्ता के कंधों को सीधे दिखाता है कि क्या कीबोर्ड दिखा रहा है।

आपके नल इशारा पहचानकर्ता प्रतिनिधि में:

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([PFXKeyboardStateListener sharedInstance].visible) {
        return YES;
    }

    return NO;
}

और PFXKeyboardStateListener.h:

@interface PFXKeyboardStateListener : NSObject
{
    BOOL _isVisible;
}

+ (PFXKeyboardStateListener *)sharedInstance;

@property (nonatomic, readonly, getter=isVisible) BOOL visible;

@end

और PFXKeyboardStateListener.m:

static PFXKeyboardStateListener *sharedInstance;

@implementation PFXKeyboardStateListener

+ (PFXKeyboardStateListener *)sharedInstance
{
    return sharedInstance;
}

+ (void)load
{
    @autoreleasepool {
        sharedInstance = [[self alloc] init];
    }
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (BOOL)isVisible
{
    return _isVisible;
}

- (void)didShow
{
    _isVisible = YES;
}

- (void)didHide
{
    _isVisible = NO;
}

- (id)init
{
    if ((self = [super init])) {
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil];
    }
    return self;
}

@end

आप कीबोर्ड श्रोता के सिंगलटन पैटर्न को अपडेट करना चाह सकते हैं, मैंने अभी तक इसे प्राप्त नहीं किया है। आशा है कि यह सभी के लिए काम करे और साथ ही साथ यह मेरे लिए भी काम करे। ^^


0

UIGestureRecognizer के प्रतिनिधि के लिए इस विधि को लागू करें:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch
{
  UIView *superview = touch.view;
  do {
    superview = superview.superview;
    if ([superview isKindOfClass:[UITableViewCell class]])
      return NO;
  } while (superview && ![superview isKindOfClass:[UITableView class]]);

  return superview != nil;
}

0

स्विफ्ट में आप इसे अंदर उपयोग कर सकते हैं

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if CheckTheTime() == true {
        // do something 
    }else{
    }
}

func CheckTheTime() -> Bool{
    return true
}

0

मेरा मामला एक uisearchbar और self.view पर uitableview सहित अलग था। मैं दृश्य पर स्पर्श करके uisearchbar कीबोर्ड को खारिज करना चाहता था।

var tapGestureRecognizer:UITapGestureRecognizer?

override func viewWillAppear(animated: Bool) {
    tapGestureRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleTap:"))
}

UISearchBar प्रतिनिधि विधियों पर:

func searchBarShouldBeginEditing(searchBar: UISearchBar) -> Bool {
    view.addGestureRecognizer(tapGestureRecognizer!)
    return true
}
func searchBarShouldEndEditing(searchBar: UISearchBar) -> Bool {
    view.removeGestureRecognizer(tapGestureRecognizer!)
    return true
}

जब उपयोगकर्ता self.view पर छूता है:

func handleTap(recognizer: UITapGestureRecognizer) {
    sampleSearchBar.endEditing(true)
    sampleSearchBar.resignFirstResponder()
}

0

स्विफ्ट 5, मई 2020।

मेरे पास एक TextField और एक TableView है जो पाठ दर्ज करते समय दिखाई देता है।

प्रारंभिक स्थिति तो मुझे 2 अलग-अलग ईवेंट चाहिए जब मैं टेबल व्यू टैप या कुछ और टैप करता हूं।

कीबोर्ड और तालिका दृश्य दिखाए जा रहे हैं

सबसे पहले हम tapGestureRecognizer जोड़ते हैं।

tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
tap.delegate = self
view.addGestureRecognizer(tap)

@objc func viewTapped() {
        view.endEditing(true)
}

फिर हम UIGestureRecognizerDelegate में निम्नलिखित चेक जोड़ते हैं:

extension StadtViewController: UIGestureRecognizerDelegate {

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view?.isDescendant(of: self.tableView) == true {
        return false
    } else {
        view.endEditing(true)
        return true
    }
}

}

यदि मैं कीबोर्ड को पहले छिपाना चाहता हूं, तो टेबल दृश्य मेरे नल के लिए दृश्यमान और उत्तरदायी रहता है।

यहां छवि विवरण दर्ज करें


-1

यह उपरोक्त उत्तर के आधार पर मेरा समाधान है ... यह मेरे लिए काम कर रहा है ...

//Create tap gesture for menu transparent view
UITapGestureRecognizer *rightTableTransparentViewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rightTableTransparentViewTapMethod:)];
[rightTableTransparentViewTap setCancelsTouchesInView:NO];
[_rightTableTransparentView addGestureRecognizer:rightTableTransparentViewTap];

- (void)rightTableTransparentViewTapMethod:(UITapGestureRecognizer *)recognizer {
    //Write your code here
}

-1

ISSUE: मेरे मामले में, मुद्दा यह था कि मैंने मूल रूप से प्रत्येक संग्रह दृश्य सेल में एक बटन रखा था और सेल को भरने के लिए बाधाओं को सेट किया था, ताकि जब सेल पर क्लिक किया गया तो वह बटन पर क्लिक करे, हालाँकि बटन फ़ंक्शन खाली था इसलिए कुछ भी नहीं था प्रतीत हो रहा है।

FIX: मैंने संग्रह व्यू सेल से बटन को हटाकर इसे ठीक किया।

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