UICollectionViewCell पर लंबी प्रेस इशारा


108

मैं सोच रहा था कि UICollectionView के एक (उपवर्ग) में एक लंबे प्रेस जेस्चर पहचानकर्ता को कैसे जोड़ा जाए। मैंने प्रलेखन में पढ़ा है कि यह डिफ़ॉल्ट रूप से जोड़ा जाता है, लेकिन मैं यह पता नहीं लगा सकता कि कैसे।

मैं क्या करना चाहता हूं: एक सेल पर लंबे समय तक प्रेस ( मेरे पास जीथब से एक कैलेंडर चीज़ है), जो सेल टैप किया गया है और फिर उसके साथ सामान करें। मुझे यह जानने की जरूरत है कि सेल क्या है। इस व्यापक प्रश्न के लिए क्षमा करें, लेकिन मुझे Google या SO पर कुछ भी बेहतर नहीं मिला

जवाबों:


220

उद्देश्य सी

अपनी myCollectionViewController.hफ़ाइल में UIGestureRecognizerDelegateप्रोटोकॉल जोड़ें

@interface myCollectionViewController : UICollectionViewController<UIGestureRecognizerDelegate>

आपकी myCollectionViewController.mफ़ाइल में:

- (void)viewDidLoad
{
    // attach long press gesture to collectionView
    UILongPressGestureRecognizer *lpgr 
       = [[UILongPressGestureRecognizer alloc]
                     initWithTarget:self action:@selector(handleLongPress:)];
    lpgr.delegate = self;
    lpgr.delaysTouchesBegan = YES;
    [self.collectionView addGestureRecognizer:lpgr];
}

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
        return;
    }
    CGPoint p = [gestureRecognizer locationInView:self.collectionView];

    NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:p];
    if (indexPath == nil){
        NSLog(@"couldn't find index path");            
    } else {
        // get the cell at indexPath (the one you long pressed)
        UICollectionViewCell* cell =
        [self.collectionView cellForItemAtIndexPath:indexPath];
        // do stuff with the cell
    }
}

तीव्र

class Some {

    @objc func handleLongPress(gesture : UILongPressGestureRecognizer!) {
        if gesture.state != .Ended {
            return
        }
        let p = gesture.locationInView(self.collectionView)

        if let indexPath = self.collectionView.indexPathForItemAtPoint(p) {
            // get the cell at indexPath (the one you long pressed)
            let cell = self.collectionView.cellForItemAtIndexPath(indexPath)
            // do stuff with the cell
        } else {
            print("couldn't find index path")
        }
    }
}

let some = Some()
let lpgr = UILongPressGestureRecognizer(target: some, action: #selector(Some.handleLongPress))

स्विफ्ट 4

class Some {

    @objc func handleLongPress(gesture : UILongPressGestureRecognizer!) {
        if gesture.state != .ended { 
            return 
        } 

        let p = gesture.location(in: self.collectionView) 

        if let indexPath = self.collectionView.indexPathForItem(at: p) { 
            // get the cell at indexPath (the one you long pressed) 
            let cell = self.collectionView.cellForItem(at: indexPath) 
            // do stuff with the cell 
        } else { 
            print("couldn't find index path") 
        }
    }
}

let some = Some()
let lpgr = UILongPressGestureRecognizer(target: some, action: #selector(Some.handleLongPress))

1
यह पहले से ही जवाब में है: UICollectionViewCell* cell = [self.collectionView cellForItemAtIndexPath:indexPath];संदर्भ यहाँ उम्मीद है कि यह सब एक सही जवाब पुरस्कार की योग्यता: डी
abbood

10
(कम से कम) ios7 के लिए आपको पहले ट्रिगर होने lpgr.delaysTouchesBegan = YES;से बचने के लिए जोड़ना होगा didHighlightItemAtIndexPath
डायनेमिकदान

7
आपने क्यों जोड़ा lpgr.delegate = self;? यह प्रतिनिधि के बिना ठीक काम करता है, जो आपने प्रदान नहीं किया है।
येवैन दुबिनिन

3
@abbood जवाब काम करता है, लेकिन मैं लंबे समय तक प्रेस पहचानकर्ता के सक्रिय होने के दौरान संग्रह (दूसरी उंगली का उपयोग करके) में ऊपर और नीचे स्क्रॉल नहीं कर सकता। क्या देता है?
पेतुर इनगी एगिल्सन

4
व्यक्तिगत रूप से, मैं करता हूं UIGestureRecognizerStateBegan, इसलिए इशारा का उपयोग तब किया जाता है जब इसे मान्यता प्राप्त होती है, न कि जब उपयोगकर्ता अपनी उंगली जारी करता है।
जेफरी सन

28

स्विफ्ट के लिए समान कोड @ abbood का कोड:

व्यूडीडलड में:

let lpgr : UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
lpgr.minimumPressDuration = 0.5
lpgr.delegate = self
lpgr.delaysTouchesBegan = true
self.collectionView?.addGestureRecognizer(lpgr)

और समारोह:

func handleLongPress(gestureRecognizer : UILongPressGestureRecognizer){

    if (gestureRecognizer.state != UIGestureRecognizerState.Ended){
        return
    }

    let p = gestureRecognizer.locationInView(self.collectionView)

    if let indexPath : NSIndexPath = (self.collectionView?.indexPathForItemAtPoint(p))!{
        //do whatever you need to do
    }

}

प्रतिनिधि मत भूलना UIGestureRecognizerDelegate


3
महान काम किया है, बस एक नोट है कि "handleLongPress:" को #selector (YourViewController.handleLongPress (_ :)) में बदला जाना चाहिए
जोसेफ

16
अच्छी तरह से काम करता है, लेकिन अगर आप चाहते हैं कि कोड न्यूनतम आग लगने के बाद बदल UIGestureRecognizerState.Endedजाए UIGestureRecognizerState.Began, तो न केवल तब जब उपयोगकर्ता अपनी उंगली उठाता है।
Crashalot

11

UICollectionView के प्रतिनिधि का उपयोग करें लंबी प्रेस घटना प्राप्त करें

आपको नीचे 3 विधि का प्रयोग करना होगा।

//UICollectionView menu delegate
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath{

   //Do something

   return YES;
}
- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender{
    //do nothing
    return NO;
}

- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender{
    //do nothing
}

नोट: यदि आप shouldShowMenuForItemAtIndexPath के लिए गलत वापस आते हैं, तो didSelectItemAtIndexPath को भी बंद कर दिया जाएगा। यह मेरे लिए समस्याग्रस्त हो गया जब मैं लंबे प्रेस बनाम एकल प्रेस के लिए दो अलग-अलग कार्रवाई चाहता था।
शैननॉएस

यह अब के लिए पदावनत विधियों है, आप का उपयोग कर सकते हैं - (UIContextMenuConfiguration *) संग्रह दृश्य: (UICollectionView *) संग्रह दृश्य संदर्भMenuConfigurationForItTAndIndexPath: (nonnull NSIndexPath *) indexPath बिंदु: - CGStation बिंदु;
विक्टर गोलट्वेनित्सा

8

कस्टम लॉन्गप्रेस जेस्चर पहचानकर्ता को जोड़ने के लिए यहाँ उत्तर हालांकि दस्तावेज के अनुसार सही हैं : कक्षा का मूल वर्ग स्क्रॉल इंटरैक्शन को संभालने के लिए UICollectionViewस्थापित करता है default long-press gesture recognizerताकि आपको अपने कस्टम टैप जेस्चर पहचानकर्ता को अपने संग्रह दृश्य से जुड़े डिफ़ॉल्ट पहचानकर्ता से लिंक करना पड़े।

निम्न कोड आपके कस्टम जेस्चर पहचानकर्ता को डिफ़ॉल्ट के साथ हस्तक्षेप करने से बचाएगा:

UILongPressGestureRecognizer* longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];

longPressGesture.minimumPressDuration = .5; //seconds
longPressGesture.delegate = self;

// Make the default gesture recognizer wait until the custom one fails.
for (UIGestureRecognizer* aRecognizer in [self.collectionView gestureRecognizers]) {
   if ([aRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
      [aRecognizer requireGestureRecognizerToFail:longPressGesture];
} 

मैं देख रहा हूँ कि आप क्या कह रहे हैं, लेकिन यह श्वेत-श्याम नहीं है, दस्तावेज़ीकरण कहता है: The parent class of UICollectionView class installs a default tap gesture recognizer and a default long-press gesture recognizer to handle scrolling interactions. You should never try to reconfigure these default gesture recognizers or replace them with your own versions.इसलिए डिफ़ॉल्ट लॉन्ग-प्रेस पहचानकर्ता स्क्रॉलिंग के लिए बना है .. जिसका अर्थ है कि इसे एक ऊर्ध्वाधर आंदोलन के साथ होना है .. ओपी पूछ नहीं रहा है उस तरह के व्यवहार के बारे में और न ही वह इसे बदलने की कोशिश कर रहा है
'12

रक्षात्मक लगने के लिए खेद है, लेकिन मैं महीनों से अपने iOS ऐप के साथ उपरोक्त कोड का उपयोग कर रहा हूं .. एक बार भी एक गड़बड़ के बारे में सोच भी नहीं सकता
abbood

@abbood यह ठीक है। मुझे नहीं पता कि पीओएल थर्ड-पार्टी कैलेंडर कंपोनेंट का उपयोग कर रहा है, लेकिन मुझे लगता है कि एक गड़बड़ को रोकना भले ही आपको लगता हो कि यह कभी नहीं हो सकता है; एक बुरा विचार नहीं हो सकता ;-)
tiguero

यदि आपको डिफ़ॉल्ट पहचानकर्ता के विफल होने का इंतजार करना चाहिए तो इसका मतलब यह नहीं है कि देरी होगी?
Crashalot

2
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];

[cell addGestureRecognizer:longPress];

और इस तरह विधि जोड़ें।

- (void)longPress:(UILongPressGestureRecognizer*)gesture
{
    if ( gesture.state == UIGestureRecognizerStateEnded ) {

        UICollectionViewCell *cellLongPressed = (UICollectionViewCell *) gesture.view;
    }
}

2

बाहरी हावभाव पहचानकर्ता के लिए और UICollectionView पर आंतरिक हावभाव पहचानकर्ताओं के साथ विरोध न करें:

अपना जेस्चर पहचानकर्ता जोड़ें, इसे सेट करें और इसके लिए कहीं पर एक संदर्भ कैप्चर करें (सबसे अच्छा विकल्प आपके उपवर्ग पर है यदि आपने UICollectionView उप-वर्ग किया है)

@interface UICollectionViewSubclass : UICollectionView <UIGestureRecognizerDelegate>    

@property (strong, nonatomic, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer;   

@end

ओवरराइड डिफ़ॉल्ट प्रारंभ तरीकों initWithFrame:collectionViewLayout:और initWithCoder:और के लिए आप लंबे समय प्रेस इशारा पहचानकर्ता पद्धति स्थापित जोड़ने

@implementation UICollectionViewSubclass

-(instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
    if (self = [super initWithFrame:frame collectionViewLayout:layout]) {
        [self setupLongPressGestureRecognizer];
    }
    return self;
}

-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        [self setupLongPressGestureRecognizer];
    }
    return self;
}

@end

अपने सेटअप विधि को लिखें ताकि यह लंबे समय तक प्रेस इशारा पहचानकर्ता को सेट करे, यह प्रतिनिधि है, UICollectionView जेस्चर पहचानकर्ता के साथ सेटअप निर्भरताएँ (इसलिए यह मुख्य इशारा है और अन्य सभी इशारे उस इशारे को पहचानने से पहले विफल होने तक प्रतीक्षा करेंगे) और देखने के लिए इशारा जोड़ें

-(void)setupLongPressGestureRecognizer
{
    _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(handleLongPressGesture:)];
    _longPressGestureRecognizer.delegate = self;

    for (UIGestureRecognizer *gestureRecognizer in self.collectionView.gestureRecognizers) {
        if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
            [gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer];
        }
    }

    [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];
}

इसके अलावा UIGestureRecognizerDelegate के तरीकों को लागू करना न भूलें जो उस इशारे को विफल कर देता है और एक साथ मान्यता की अनुमति देता है (आपको इसे लागू करने की आवश्यकता हो सकती है या नहीं, यह आपके लिए अन्य जेस्चर पहचानकर्ताओं पर निर्भर करता है या आंतरिक जेस्चर पहचानकर्ताओं पर निर्भर करता है।

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

    return NO;
}

इसके लिए साख LXReorderableCollectionViewFlowLayout के आंतरिक कार्यान्वयन में जाती है


यह वही नृत्य है जो मैंने अपने स्नैपचैट क्लोन के लिए किया था। अहह सच्चा प्यार
बेंजामिनहालॉक

1

स्विफ्ट 5:

private func setupLongGestureRecognizerOnCollection() {
    let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gestureRecognizer:)))
    longPressedGesture.minimumPressDuration = 0.5
    longPressedGesture.delegate = self
    longPressedGesture.delaysTouchesBegan = true
    collectionView?.addGestureRecognizer(longPressedGesture)
}

@objc func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
    if (gestureRecognizer.state != .began) {
        return
    }

    let p = gestureRecognizer.location(in: collectionView)

    if let indexPath = collectionView?.indexPathForItem(at: p) {
        print("Long press at item: \(indexPath.row)")
    }
}

इसके अलावा UIGestureRecognizerDelegate को लागू करने और viewDidLoad से या जहाँ भी आपको इसे कॉल करने की आवश्यकता हो, सेटअपLongGestureRecognizerOnCollection को लागू करना न भूलें।


0

शायद, UILongPressGestureRecognizer का उपयोग करना सबसे व्यापक समाधान है। लेकिन मैं इसके साथ दो कष्टप्रद परेशानियों का सामना करता हूं:

  • कभी-कभी यह पहचानकर्ता गलत तरीके से काम करता है जब हम अपना स्पर्श कर रहे होते हैं;
  • पहचानकर्ता अन्य स्पर्श क्रियाओं को स्वीकार करता है, इसलिए हम अपने यूआईसीओलेक्शन व्यू के हाइलाइट कॉलबैक का उचित तरीके से उपयोग नहीं कर सकते हैं।

मुझे एक छोटे से bruteforce सुझाव देते हैं, लेकिन यह आवश्यक सुझाव के रूप में काम कर रहा है:

हमारे सेल पर लंबे समय के लिए कॉलबैक विवरण की घोषणा:

typealias OnLongClickListener = (view: OurCellView) -> Void

चरों के साथ UICollectionViewCell का विस्तार करना (हम इसका नाम OurCellView रख सकते हैं, उदाहरण के लिए):

/// To catch long click events.
private var longClickListener: OnLongClickListener?

/// To check if we are holding button pressed long enough.
var longClickTimer: NSTimer?

/// Time duration to trigger long click listener.
private let longClickTriggerDuration = 0.5

हमारे सेल वर्ग में दो विधियाँ जोड़ना:

/**
 Sets optional callback to notify about long click.

 - Parameter listener: A callback itself.
 */
func setOnLongClickListener(listener: OnLongClickListener) {
    self.longClickListener = listener
}

/**
 Getting here when long click timer finishs normally.
 */
@objc func longClickPerformed() {
    self.longClickListener?(view: self)
}

और यहां स्पर्श की घटनाओं को ओवरराइड करना:

/// Intercepts touch began action.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    longClickTimer = NSTimer.scheduledTimerWithTimeInterval(self.longClickTriggerDuration, target: self, selector: #selector(longClickPerformed), userInfo: nil, repeats: false)
    super.touchesBegan(touches, withEvent: event)
}

/// Intercepts touch ended action.
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    longClickTimer?.invalidate()
    super.touchesEnded(touches, withEvent: event)
}

/// Intercepts touch moved action.
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    longClickTimer?.invalidate()
    super.touchesMoved(touches, withEvent: event)
}

/// Intercepts touch cancelled action.
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
    longClickTimer?.invalidate()
    super.touchesCancelled(touches, withEvent: event)
}

फिर कॉलबैक श्रोता घोषित करने वाले हमारे संग्रह दृश्य के नियंत्रक में कहीं:

let longClickListener: OnLongClickListener = {view in
    print("Long click was performed!")
}

और अंत में cellForItemAtIndexPath में हमारे सेल के लिए कॉलबैक सेटिंग:

/// Data population.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
    let castedCell = cell as? OurCellView
    castedCell?.setOnLongClickListener(longClickListener)

    return cell
}

अब हम अपनी कोशिकाओं पर लंबी क्लिक क्रियाओं को रोक सकते हैं।

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