113

UICollectionView (のサブクラス) に長押しジェスチャ認識機能を追加する方法を知りたいと思っていました。デフォルトで追加されているというドキュメントを読みましたが、その方法がわかりません。

私がやりたいことは、セルを長押しして(githubのカレンダーを持っています)、どのセルがタップされているかを取得してから、それを処理することです。どのセルが長押しされているかを知る必要があります。この幅広い質問で申し訳ありませんが、GoogleでもSOでもこれ以上のものは見つかりませんでした

4

9 に答える 9

14

スイフト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 を実装し、setupLongGestureRecognizerOnCollection を viewDidLoad または呼び出す必要がある場所から呼び出すことを忘れないでください。

于 2020-06-06T14:46:26.857 に答える
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];
} 
于 2013-09-17T12:15:26.463 に答える
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の内部実装に送られます

于 2015-12-28T15:56:55.097 に答える
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;
    }
}
于 2013-09-17T11:38:08.360 に答える
0

おそらく、UILongPressGestureRecognizerを使用することが最も広く普及しているソリューションです。しかし、私はそれで2つの厄介な問題に遭遇します:

  • タッチを動かしているときに、この認識機能が正しく動作しないことがあります。
  • レコグナイザーは他のタッチ アクションをインターセプトするため、適切な方法で 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

cell クラスに 2 つのメソッドを追加します。

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

これで、セルに対する長いクリック アクションをインターセプトできるようになりました。

于 2016-08-12T16:26:21.460 に答える