UITableViewを長押し


回答:


427

まず、長押しジェスチャー認識機能をテーブルビューに追加します。

UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] 
  initWithTarget:self action:@selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];

次に、ジェスチャーハンドラーで:

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    CGPoint p = [gestureRecognizer locationInView:self.myTableView];

    NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
    if (indexPath == nil) {
        NSLog(@"long press on table view but not on a row");
    } else if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        NSLog(@"long press on table view at row %ld", indexPath.row);
    } else {
        NSLog(@"gestureRecognizer.state = %ld", gestureRecognizer.state);
    }
}

これは、ユーザーによるセルの通常のタップを妨げないように注意する必要があり、handleLongPress複数回起動する可能性があることにも注意してください(これは、ジェスチャー認識機能の状態の変化が原因です)。


1
驚くばかり !!!どうもありがとう!しかし、最後の小さな質問:タッチが終了したときに、handleLongPressメソッドが呼び出されるのはなぜですか?
foOg

111
修正:ジェスチャーのさまざまな状態(開始、変更、終了など)を示すために複数回起動します。したがって、ハンドラメソッドで、ジェスチャの各状態でアクションを実行しないように、ジェスチャレコグナイザの状態プロパティを確認してください。例:if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ...

3
忘れないでください。ジェスチャーレコグナイザーをインターフェイスビルダーで直接UI要素に追加し、IBActionメソッドを介して接続できるようになったため、この答えはさらに簡単になりました;-)(レコグナイザーをにアタッチすることを忘れUITableViewないでくださいUITableViewCell...)

10
また、class.hファイルのUIGestureRecognizerDelegateプロトコルを確認してください
Vaquita

1
テーブルビューがセルに移動しないようにする方法( 'didSelectRowAtIndexPath'を実装している場合)
Marchy

46

私はAnna-Kareninaの回答を使用しましたが、非常に深刻なバグでほぼ問題なく動作します。

セクションを使用している場合、セクションタイトルを長押しするとそのセクションの最初の行を押すと誤った結果が表示されます。以下の修正バージョンを追加しました(ジェスチャーの状態に基づくダミーコールのフィルタリングを含め、アンナカレニーナの提案)。

- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {

        CGPoint p = [gestureRecognizer locationInView:self.tableView];

        NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
        if (indexPath == nil) {
            NSLog(@"long press on table view but not on a row");
        } else {
            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
            if (cell.isHighlighted) {
                NSLog(@"long press on table view at section %d row %d", indexPath.section, indexPath.row);
            }
        }
    }
}

こんにちは@marmor:ユーザーが触れたビューの一部のみを識別することは可能ですか?
Manthan

ねえ、あなたはそれのためにhitTestを使うことができます(developer.apple.com/library/ios/documentation/uikit/reference/…)。使用方法の例については、この回答を確認してください:stackoverflow.com/a/2793253/819355
marmor

受け入れられた答えが機能する間。画面上でドラッグしている間、ログとともに複数の火災を記録します。この答えはしません。正当なコピーと貼り付けの答え。ありがとうございました。
ChrisOSX 2017年

29

Swift 5での回答(SwiftでのRickyの回答の続き)

UIGestureRecognizerDelegateViewControllerに追加します

 override func viewDidLoad() {
    super.viewDidLoad()

    //Long Press
    let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
    longPressGesture.minimumPressDuration = 0.5
    self.tableView.addGestureRecognizer(longPressGesture)
 }

そして機能:

@objc func handleLongPress(longPressGesture: UILongPressGestureRecognizer) {
    let p = longPressGesture.location(in: self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: p)
    if indexPath == nil {
        print("Long press on table view, not row.")
    } else if longPressGesture.state == UIGestureRecognizer.State.began {
        print("Long press on row, at \(indexPath!.row)")
    }
}

20

ドーン・ソングの答えとマルモールの答えを組み合わせた明確な指示があります。

長いプレスジェスチャー認識機能をドラッグして、テーブルセルにドロップします。左側のリストの一番下にジャンプします。

ここに画像の説明を入力してください

次に、ボタンを接続するのと同じ方法でジェスチャ認識機能を接続します。 ここに画像の説明を入力してください

アクションハンドラにMarmorのコードを追加します

- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {

    CGPoint p = [sender locationInView:self.tableView];

    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
    if (indexPath == nil) {
        NSLog(@"long press on table view but not on a row");
    } else {
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
        if (cell.isHighlighted) {
            NSLog(@"long press on table view at section %d row %d", indexPath.section, indexPath.row);
        }
    }
}

}


2
私の意見では最良の答え
Asen Kasimov

8
長押しジェスチャー認識機能は、テーブルビューセルではなくテーブルビューに適用する必要があります。テーブルビューセルにドロップすると、行0のみが長押しされます。
Alex

14

次に示すように、認識機能をセルに直接追加する方が効率的です。

TableViewセルをタップ&ホールドし、その時と今

(一番下の例にスクロールしてください)


7
各行に新しいジェスチャーレコグナイザーオブジェクトを割り当てることは、テーブル全体の単一のレコグナイザーよりもどのように効率的ですか?
user2393462435

7
ただし、デキューが正しく機能している場合は、セルがいくつか作成されるだけです。
アリ

11

スウィフトでの回答:

UIGestureRecognizerDelegateUITableViewController にデリゲートを追加します。

UITableViewController内:

override func viewDidLoad() {
    super.viewDidLoad()

    let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
    longPressGesture.minimumPressDuration = 1.0 // 1 second press
    longPressGesture.delegate = self
    self.tableView.addGestureRecognizer(longPressGesture)

}

そして機能:

func handleLongPress(longPressGesture:UILongPressGestureRecognizer) {

    let p = longPressGesture.locationInView(self.tableView)
    let indexPath = self.tableView.indexPathForRowAtPoint(p)

    if indexPath == nil {
        print("Long press on table view, not row.")
    }
    else if (longPressGesture.state == UIGestureRecognizerState.Began) {
        print("Long press on row, at \(indexPath!.row)")
    }

}

6

Anna Kareninaの優れた回答に基づいて、UITableViewに小さなカテゴリをまとめました。

このように、通常のテーブルビューを処理するときに慣れているような便利なデリゲートメソッドがあります。見てみな:

//  UITableView+LongPress.h

#import <UIKit/UIKit.h>

@protocol UITableViewDelegateLongPress;

@interface UITableView (LongPress) <UIGestureRecognizerDelegate>
@property(nonatomic,assign)   id <UITableViewDelegateLongPress>   delegate;
- (void)addLongPressRecognizer;
@end


@protocol UITableViewDelegateLongPress <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didRecognizeLongPressOnRowAtIndexPath:(NSIndexPath *)indexPath;
@end



//  UITableView+LongPress.m

#import "UITableView+LongPress.h"

@implementation UITableView (LongPress)
@dynamic delegate;

- (void)addLongPressRecognizer {
    UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
                                          initWithTarget:self action:@selector(handleLongPress:)];
    lpgr.minimumPressDuration = 1.2; //seconds
    lpgr.delegate = self;
    [self addGestureRecognizer:lpgr];
}


- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    CGPoint p = [gestureRecognizer locationInView:self];

    NSIndexPath *indexPath = [self indexPathForRowAtPoint:p];
    if (indexPath == nil) {
        NSLog(@"long press on table view but not on a row");
    }
    else {
        if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
            // I am not sure why I need to cast here. But it seems to be alright.
            [(id<UITableViewDelegateLongPress>)self.delegate tableView:self didRecognizeLongPressOnRowAtIndexPath:indexPath];
        }
    }
}

これをUITableViewControllerで使用する場合は、おそらくサブクラス化して新しいプロトコルに準拠する必要があります。

それは私にとってはうまくいきます、それが他の人を助けることを願っています!


委任とカテゴリパターンのすばらしい使用法
valeCocoa 2017

5

Swift 3の回答。最新の構文を使用し、他の回答を組み込み、不要なコードを排除します。

override func viewDidLoad() {
    super.viewDidLoad()
    let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(tablePressed))
    tableView.addGestureRecognizer(recognizer)
 }

@IBAction func tablePressed(_ recognizer: UILongPressGestureRecognizer) {
    let point = recognizer.location(in: tableView)

    guard recognizer.state == .began,
          let indexPath = tableView.indexPathForRow(at: point),
          let cell = tableView.cellForRow(at: indexPath),
          cell.isHighlighted
    else {
        return
    }

    // TODO
}

2

UILongPressGestureRecognizerをストーリーボードの特定のプロトタイプセルに追加し、ジェスチャーをviewControllerの.mファイルにプルして、アクションメソッドを作成します。私が言ったようにそれを作りました。


もう少し説明してもらえますか?プロトタイプセルをVCのプロパティにしましたか?
イーサンパーカー、

-2

touchesBeganでUITouchタイムスタンププロパティを使用して、タイマーを起動するか、touchesEndedが発生したときにタイマーを停止します。


回答ありがとうございます。どの行がタッチに関係しているのかをどのように検出できますか?
foOg

私は間違っているかもしれませんが、あなたがそれをするのを助けるために何も提供されていません。[tableView indexPathsForVisibleRows]を使用して現在表示されているセルのインデックスを取得する必要があります。次に、いくつかの計算(上からのtableViewオフセット+行のX倍)を使用して、指の座標がどこにあるかを確認します。行。
Thomas Joulin

もっと簡単な方法があると私は確信しています。別のアイデアがあれば、私はここにいます:)
foOg

もっと簡単なことが可能かどうかも知りたいです。しかし、私はそうは思わない、それは主にAppleが私たちにインタラクションを処理することを望んでいる方法ではないからだ...この「クイックアクセスメニュー」を考えるAndroidの方法のように見える。私のアプリなら、Twitterアプリのように扱います。左にスワイプするとオプションが表示されます
Thomas Joulin

はい、それについて考えたので、長押しイベントで本当にそれができない場合は、スワイプ方式を使用します。しかし、スタックオーバーフローの誰かがそれをしたのかもしれません...
10:14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.