Nhấn và giữ trên UITableView


191

Tôi muốn xử lý một cú nhấn dài vào một UITableViewCellđể in một "menu truy cập nhanh". Đã có ai đó làm điều này?

Riêng cử chỉ nhận ra UITableView?

Câu trả lời:


427

Đầu tiên, thêm trình nhận dạng cử chỉ nhấn dài vào chế độ xem bảng:

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

Sau đó, trong xử lý cử chỉ:

-(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);
    }
}

Bạn phải cẩn thận với điều này để nó không can thiệp vào thao tác gõ bình thường của người dùng và cũng lưu ý rằng handleLongPresscó thể bắn nhiều lần (điều này sẽ do thay đổi trạng thái nhận dạng cử chỉ).


1
Tuyệt vời !!! Cảm ơn rất nhiều! Nhưng một câu hỏi nhỏ cuối cùng: Tại sao phương thức handleLongPress lại gọi khi cảm ứng kết thúc ???
foOg

111
Sửa chữa: nó bắn nhiều lần để chỉ ra các trạng thái khác nhau của cử chỉ (bắt đầu, thay đổi, kết thúc, v.v.). Vì vậy, trong phương thức xử lý, kiểm tra thuộc tính trạng thái của bộ nhận dạng cử chỉ để tránh thực hiện hành động ở mỗi trạng thái của cử chỉ. Vd : if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ....

3
Đừng quên, giờ đây trình nhận dạng cử chỉ có thể được thêm trực tiếp vào các thành phần UI trong Trình tạo giao diện và được kết nối thông qua phương thức IBAction, vì vậy câu trả lời này thậm chí còn dễ dàng hơn ;-) (chỉ cần nhớ gắn trình nhận dạng vào UITableView, chứ không phải UITableViewCell...)

10
Đồng thời xác nhận với giao thức UIGestureRecognizerDelegate trong tệp
class.h

1
Làm thế nào để bạn ngăn chế độ xem bảng điều hướng vào ô (nếu bạn đã thực hiện 'didSelectRowAtIndexPath'?)
Marchy

46

Tôi đã sử dụng câu trả lời của Anna-Karenina và nó hoạt động gần như tuyệt vời với một lỗi rất nghiêm trọng.

Nếu bạn đang sử dụng các phần, nhấn và giữ tiêu đề phần sẽ cho bạn kết quả sai khi nhấn hàng đầu tiên trên phần đó, tôi đã thêm một phiên bản cố định bên dưới (bao gồm lọc các cuộc gọi giả dựa trên trạng thái cử chỉ, mỗi Đề nghị 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);
            }
        }
    }
}

Xin chào @marmor: Tôi muốn hỏi rằng có thể chỉ xác định một phần của chế độ xem mà người dùng đã chạm vào không?
Thần chú

Xin chào, bạn có thể sử dụng hitTest cho điều đó ( developer.apple.com/l Library / ios / document / uikit / report / trộm ). Kiểm tra câu trả lời này để biết ví dụ về cách sử dụng: stackoverflow.com/a/2793253/819355
marmor

Trong khi câu trả lời được chấp nhận hoạt động. Nó ghi nhật ký nhiều đám cháy, cùng với việc ghi nhật ký trong khi kéo trên màn hình. Câu trả lời này không. Một bản sao hợp pháp và dán câu trả lời. Cảm ơn bạn.
ChrisOSX

29

Trả lời trong Swift 5 (Tiếp tục câu trả lời của Ricky trong Swift)

Thêm vào UIGestureRecognizerDelegateViewContoder của bạn

 override func viewDidLoad() {
    super.viewDidLoad()

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

Và chức năng:

@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

Dưới đây là hướng dẫn được làm rõ kết hợp câu trả lời của Dawn Song và câu trả lời của Marmor.

Kéo một Trình nhận dạng cử chỉ dài và thả nó vào Bảng di động của bạn. Nó sẽ nhảy xuống cuối danh sách bên trái.

nhập mô tả hình ảnh ở đây

Sau đó kết nối bộ nhận dạng cử chỉ giống như cách bạn kết nối một nút. nhập mô tả hình ảnh ở đây

Thêm mã từ Marmor trong trình xử lý hành động

- (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
Câu trả lời hay nhất theo ý kiến ​​của tôi
Asen Kasimov 4/12/2015

8
Long Press Gesture Recognizer nên được áp dụng cho chế độ xem bảng chứ không phải ô xem bảng. Thả nó vào ô xem bảng sẽ chỉ có hàng 0 nghe nhấn lâu.
Alex

14

Có vẻ hiệu quả hơn để thêm bộ nhận dạng trực tiếp vào ô như hiển thị ở đây:

Chạm và giữ cho các ô của TableView, sau đó và ngay bây giờ

(cuộn đến ví dụ ở phía dưới)


7
Làm thế nào có thể phân bổ một đối tượng nhận dạng cử chỉ mới cho mỗi hàng hiệu quả hơn một công cụ nhận dạng duy nhất cho toàn bộ bảng?
dùng2393462435

7
Hãy nhớ rằng chỉ có một vài ô được tạo nếu dequeue hoạt động chính xác.
Kiến

11

Trả lời bằng Swift:

Thêm đại biểu UIGestureRecognizerDelegatevào UITableViewControll của bạn.

Trong UITableViewCont kiểm soát:

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)

}

Và chức năng:

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

Tôi kết hợp một danh mục nhỏ trên UITableView dựa trên câu trả lời xuất sắc của Anna Karenina.

Như thế này, bạn sẽ có một phương thức ủy nhiệm thuận tiện như bạn đã quen khi xử lý các chế độ xem bảng thông thường. Kiểm tra xem nó:

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

Nếu bạn muốn sử dụng điều này trong UITableViewCont kiểm soát, có lẽ bạn cần phải phân lớp và tuân thủ giao thức mới.

Nó hoạt động rất tốt cho tôi, hy vọng nó sẽ giúp người khác!


Cách sử dụng tuyệt vời của mẫu ủy nhiệm và danh mục
valeCocoa

5

Trả lời Swift 3, sử dụng cú pháp hiện đại, kết hợp các câu trả lời khác và loại bỏ mã không cần thiết.

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

Chỉ cần thêm UILongPressGestureRecognizer vào ô nguyên mẫu đã cho trong bảng phân cảnh, sau đó kéo cử chỉ vào tệp .m của viewContoder để tạo phương thức hành động. Tôi đã làm nó như tôi đã nói.


Bạn có thể giải thích thêm một chút? Bạn đã biến ô nguyên mẫu thành một thuộc tính trong VC của mình chưa?
Ethan Parker

-2

Sử dụng thuộc tính dấu thời gian UITouch trong touchesBegan để khởi chạy bộ đếm thời gian hoặc dừng nó khi chạm vào Đã bị bắn


Cảm ơn câu trả lời của bạn nhưng làm thế nào tôi có thể phát hiện hàng nào được quan tâm bằng cảm ứng?
foOg

Tôi có thể sai, nhưng không có gì được cung cấp để giúp bạn làm điều đó. Bạn sẽ phải lấy chỉ mục của các ô hiển thị hiện tại bằng [tableView indexPathsForVisibleRows] và sau đó, bằng cách sử dụng một số tính toán (bảngView của bạn được bù từ đầu + X lần các hàng) bạn sẽ biết rằng tọa độ của ngón tay của bạn nằm trên đó hàng.
Thomas Joulin

Tôi chắc chắn rằng có một cách dễ dàng hơn để làm điều đó, dù sao nếu bạn có ý tưởng khác, tôi sẽ ở đây :)
foOg

Tôi cũng rất vui khi biết điều gì đó dễ dàng hơn. Nhưng tôi không nghĩ là có, chủ yếu là vì đó không phải là cách Apple muốn chúng tôi xử lý các tương tác ... Có vẻ như cách Android nghĩ về "menu truy cập nhanh" này. Nếu đó là ứng dụng của tôi, tôi sẽ xử lý nó như ứng dụng Twitter. Vuốt sang trái sẽ hiển thị các tùy chọn
Thomas Joulin

Vâng, tôi đã nghĩ về điều đó, vì vậy nếu tôi thực sự không thể làm điều đó với một sự kiện báo chí dài, tôi sẽ sử dụng phương pháp vuốt. Nhưng, có lẽ ai đó trong ngăn xếp tràn đã làm nó ...
foOg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.