it-swarm.com.ru

Длительное нажатие на UICollectionViewCell

Мне было интересно, как добавить распознаватель жестов длинного нажатия в (подкласс) UICollectionView. Я прочитал в документации, что она добавлена ​​по умолчанию, но я не могу понять, как. 

То, что я хочу сделать, это: Длительное нажатие на ячейку ( у меня есть примочка календаря от github ), узнать, какая ячейка нажата, и затем что-то делать с ней. Мне нужно знать, какая клетка долго нажата. Извините за этот широкий вопрос, но я не смог найти ничего лучшего ни в Google, ни в SO 

96
Oscar Apeland

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))

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))
199
abbood

Тот же код @ код 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

22
Guilherme de Freitas

Используйте делегат 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
}
9
liuyuning

Здесь приведены ответы на добавление настраиваемого распознавателя жестов при длинном нажатии однако в соответствии с документацией здесь : родительский класс класса 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];
} 
8
tiguero
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
satheeshwaran

Чтобы иметь внешний распознаватель жестов и не конфликтовать с внутренними распознавателями жестов в 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

2
Dmitry Fantastik

Возможно, использование 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
}

Теперь мы можем перехватывать длительные клики по нашим ячейкам. 

0