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의 답변을 사용했으며 매우 심각한 버그로 거의 작동합니다.

섹션을 사용하는 경우 섹션 제목을 길게 누르면 해당 섹션의 첫 번째 행을 눌렀을 때 잘못된 결과를 얻을 수 있습니다. 아래에 고정 버전을 추가했습니다 (제스처 상태에 따라 더미 통화 필터링 포함). 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

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

Dawn Song의 답변과 Marmor의 답변을 결합한 명확한 지침이 있습니다.

길게 누르는 제스처 인식기를 끌어 테이블 셀에 놓으십시오. 왼쪽 목록의 맨 아래로 이동합니다.

여기에 이미지 설명을 입력하십시오

그런 다음 단추를 연결하는 것과 같은 방식으로 동작 인식기를 연결하십시오. 여기에 이미지 설명을 입력하십시오

액션 핸들러에서 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
큐 제거가 올바르게 작동하면 몇 개의 셀만 생성된다는 것을 기억하십시오.
Ants

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

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의 속성으로 만들었습니까?
Ethan Parker

-2

touchesBegan에서 UITouch 타임 스탬프 속성을 사용하여 타이머를 시작하거나 touchesEnded가 시작될 때 타이머를 중지


귀하의 답변에 감사하지만 터치에 관련된 행을 어떻게 감지 할 수 있습니까?
foOg

내가 틀렸을 수도 있지만, 그렇게하는 데 도움이되는 것은 없습니다. [tableView indexPathsForVisibleRows]를 사용하여 현재 보이는 셀의 인덱스를 얻은 다음 일부 계산 (tableView 오프셋을 상단에서 + X 곱하기 행)을 사용하여 손가락의 좌표가 어느 것인지 알 수 있습니다 열.
Thomas Joulin

어쨌든 다른 아이디어가 있다면 내가 여기있을거야 :)
foOg

더 쉬운 것이 가능한지 알고 기쁩니다. 하지만 애플이 우리가 인터랙션을 처리하기를 원하는 방식이 아니기 때문이라고 생각하지 않습니다.이 "빠른 액세스 메뉴"를 생각하는 안드로이드 방식처럼 보입니다. 내 앱이라면 Twitter 앱처럼 처리하겠습니다. 왼쪽으로 스 와이프하면 옵션이 표시됩니다.
Thomas Joulin

예, 그것에 대해 생각했기 때문에 실제로 긴 프레스 이벤트로 할 수 없으면 스 와이프 방법을 사용합니다. 그러나 스택 오버플로에있는 누군가가
그랬을
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.