Длительное нажатие жест на UICollectionViewCell
Мне было интересно, как добавить распознаватель жестов длительного нажатия в (подкласс) UICollectionView. Я читал в документации, что он добавляется по умолчанию, но я не могу понять, как это сделать.
то, что я хочу сделать, это:
Длительное нажатие на ячейку ( у меня есть календарная штука от github), получить, какая ячейка прослушивается, а затем делать вещи с ним. Мне нужно знать, какая клетка долго сжимается. Извините за этот широкий вопрос, но я не мог найти ничего лучше ни в google, ни так
7 ответов:
С
в своем добавить
UIGestureRecognizerDelegateпротокол@interface myCollectionViewController : UICollectionViewController<UIGestureRecognizerDelegate>в своем
myCollectionViewController.mfile:- (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))Swift 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))
тот же код @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)функция:
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класс устанавливает adefault 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]; }
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 вам нужно:
добавить распознаватель жестов, настроить его и захватить ссылку на него где-то (лучший вариант находится на вашем подклассе, если вы подкласс 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написать свое метод установки таким образом, он создает экземпляр Long press gesture recognizer, устанавливает его делегат, устанавливает зависимости с помощью UICollectionView gesture recognizer (так что это будет основной жест, и все другие жесты будут ждать, пока этот жест не будет распознан) и добавляет жест в представление
-(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 является наиболее распространенным решением. Но я сталкиваюсь с этим двумя досадными неприятностями:
- иногда этот распознаватель работает неправильно, когда мы перемещаем наше прикосновение;
- распознаватель перехватывает другие действия касания, поэтому мы не можем использовать обратные вызовы подсветки нашего UICollectionView надлежащим образом.
позвольте мне предложить один немного брутфорс, но работает так, как это требуется предложение:
объявление описания обратного вызова для длинного щелчка по нашей ячейке:
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 }теперь мы можем перехватывать длинные действия щелчка на наших клетках.
Comments