在UICollectionViewCell上长按手势

我想知道如何将一个长按手势识别器添加到(的子类)UICollectionView。 我在文档中看到它是默认添加的,但我不知道如何。

我想要做的是:长按一个单元格( 我有一个来自github的日历thingy ),获取哪个单元格,然后用它做东西。 我需要知道什么细胞是压抑的。 对不起,这个广泛的问题,但我找不到任何更好的谷歌或SO

Objective-C的

在你的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)) 

相同的代码@ abbood的Swift代码:

在viewDidLoad中:

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

而function:

 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

使用UICollectionView的代表接收长按事件

下面你必须impl 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 } 

根据这里的文档, 在这里添加一个自定义的longpress手势识别器的答案是正确的: UICollectionView类的父类安装default long-press gesture recognizer来处理滚动的交互,所以你必须链接你的自定义轻拍手势识别器相关联的默认识别器与您的collections视图。

以下代码将避免您的自定义手势识别器干扰默认的手势:

 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]; } 
 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; } } 

要具有外部手势识别器,并且不与UICollectionView上的内部手势识别器冲突,您需要:

添加你的手势识别器,设置它并为它捕获一个引用(最好的select是你的子类,如果你分类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的内部实现

也许,使用UILongPressGestureRecognizer是最普遍的解决scheme。 但是我遇到了两个烦人的麻烦:

  • 有时当我们移动我们的触摸时,这个识别器的工作方式不正确;
  • 识别器拦截其他的触摸动作,所以我们不能以正确的方式使用我们的UICollectionView的高亮callback。

让我build议一个有点暴力,但工作,因为它需要的build议:

声明一个callback描述,长按一下我们的单元格:

typealias OnLongClickListener = (view: OurCellView) -> Void

使用variables扩展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) } 

然后在我们的集合视图的控制器中的某处声明callback监听器:

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

最后在cellForItemAtIndexPath设置callback为我们的单元格:

 /// 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 } 

现在我们可以截取我们细胞上的长时间点击行为。