กดค้างที่ UITableView


191

ฉันต้องการกดแบบยาวUITableViewCellเพื่อพิมพ์ "เมนูการเข้าถึงด่วน" มีคนทำเช่นนี้แล้ว?

โดยเฉพาะท่าทางที่รับรู้ได้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
เยี่ยมมาก !!! ขอบคุณมาก! แต่คำถามสุดท้าย: ทำไมวิธีการจัดการ LongPress จึงเรียกเมื่อการสัมผัสสิ้นสุดลง ???
foOg

111
การแก้ไข: มันยิงหลาย ๆ ครั้งเพื่อระบุสถานะที่แตกต่างของท่าทาง (เริ่ม, เปลี่ยน, สิ้นสุด, ฯลฯ ) ดังนั้นในวิธีการจัดการให้ตรวจสอบคุณสมบัติสถานะของตัวจำแนกท่าทางเพื่อหลีกเลี่ยงการดำเนินการในแต่ละสถานะของท่าทาง if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ...เช่น:

3
อย่าลืมว่าตอนนี้คุณสามารถเพิ่มตัวจดจำลายเส้นในองค์ประกอบ UI ได้โดยตรงในตัวสร้างส่วนต่อประสานและเชื่อมต่อผ่านวิธีการ IBAction ดังนั้นคำตอบนี้ง่ายยิ่งขึ้น ;-) (เพียงจำไว้ว่าให้แนบตัวจำแนกลายมือกับ... UITableViewไม่ใช่UITableViewCell)

10
ยืนยันไปยัง UIGestureRecognizerDelegate โปรโตคอลในไฟล์ class.h
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);
            }
        }
    }
}

สวัสดี @ มารยาท: ฉันต้องการถามว่ามันเป็นไปได้ที่จะระบุเพียงบางส่วนของมุมมองที่ผู้ใช้สัมผัส?
Manthan

สวัสดีคุณสามารถใช้ hitTest สำหรับสิ่งนั้นได้ ( developer.apple.com/library/ios/documentation/uikit/reference/ ...... ) ตรวจสอบคำตอบนี้สำหรับตัวอย่างเกี่ยวกับวิธีใช้: stackoverflow.com/a/2793253/819355
marmor

ในขณะที่คำตอบที่ยอมรับใช้งานได้ มันบันทึกหลายไฟพร้อมด้วยการบันทึกในขณะที่ลากบนหน้าจอ คำตอบนี้ไม่ได้ สำเนาที่ถูกต้องและวางคำตอบ ขอบคุณ.
ChrisOSX

29

คำตอบใน Swift 5 (คำตอบต่อเนื่องของ Ricky ใน Swift)

เพิ่มUIGestureRecognizerDelegateไปยัง ViewController ของคุณ

 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 เท่านั้น
อเล็กซ์

14

ดูเหมือนว่าจะมีประสิทธิภาพมากกว่าในการเพิ่มตัวจำแนกลายมือลงในเซลล์โดยตรงดังที่แสดงที่นี่:

แตะค้างไว้ที่เซลล์ TableView จากนั้นและทันที

(เลื่อนไปที่ตัวอย่างที่ด้านล่าง)


7
วิธีการจัดสรรวัตถุตัวรู้จำท่าทางใหม่สำหรับแต่ละแถวจะมีประสิทธิภาพมากกว่าตัวจำแนกลายมือเดียวสำหรับทั้งตารางได้อย่างไร
user2393462435

7
โปรดจำไว้ว่ามีเพียงไม่กี่เซลล์ที่สร้างขึ้นหาก dequeue ทำงานอย่างถูกต้อง
มด

11

คำตอบใน Swift:

เพิ่มผู้รับมอบสิทธิ์UIGestureRecognizerDelegateลงใน UITableViewController ของคุณ

ภายใน 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

ฉันรวบรวมหมวดหมู่เล็ก ๆ บน UITableView ตามคำตอบที่ยอดเยี่ยมของ Anna Karenina

เช่นนี้คุณจะมีวิธีการมอบหมายที่สะดวกเหมือนที่คุณคุ้นเคยเมื่อจัดการกับมุมมองตารางปกติ ลองดูสิ:

//  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 คุณอาจต้อง subclass และสอดคล้องกับโปรโตคอลใหม่

มันใช้งานได้ดีสำหรับฉันหวังว่าจะช่วยคนอื่น ๆ !


การใช้งานที่น่าอัศจรรย์ของรูปแบบการมอบหมายและหมวดหมู่
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 ไปยังเซลล์ต้นแบบที่กำหนดในกระดานเรื่องราวจากนั้นดึงท่าทางไปยังไฟล์. m ของ viewController เพื่อสร้างวิธีการดำเนินการ ฉันทำมันตามที่ฉันพูด


คุณช่วยอธิบายอีกหน่อยได้ไหม? คุณทำให้เซลล์ต้นแบบเป็นคุณสมบัติใน VC ของคุณหรือไม่
Ethan Parker

-2

ใช้คุณสมบัติการประทับเวลาของ UITouch ใน touchesBegan เพื่อเปิดตัวจับเวลาหรือหยุดมันเมื่อ touchesEnded โดนไล่ออก


ขอบคุณสำหรับคำตอบของคุณ แต่ฉันจะตรวจสอบแถวที่เกี่ยวข้องกับการสัมผัสได้อย่างไร
foOg

ฉันอาจจะผิด แต่ไม่มีอะไรให้ไว้เพื่อช่วยคุณ คุณจะต้องรับดัชนีของเซลล์ที่มองเห็นได้ในปัจจุบันด้วย [tableView indexPathsForVisibleRows] จากนั้นใช้การคำนวณบางอย่าง (tableView ของคุณชดเชยจากด้านบน + X คูณแถว) คุณจะรู้ว่าพิกัดของนิ้วของคุณอยู่ในตำแหน่งใด แถว.
Thomas Joulin

ฉันแน่ใจว่ามีวิธีที่ง่ายกว่าในการทำเช่นนั้นถ้าคุณมีความคิดอื่นฉันจะอยู่ที่นี่ :)
สำหรับ

ฉันยินดีที่จะรู้เช่นกันหากเป็นไปได้ แต่ฉันไม่คิดว่ามีส่วนใหญ่เป็นเพราะไม่ใช่วิธีที่แอปเปิ้ลต้องการให้เราจัดการกับการโต้ตอบ ... ดูเหมือนว่าวิธีคิดของ Android "เมนูการเข้าถึงด่วน" นี้ หากเป็นแอพของฉันฉันจะจัดการเหมือนแอพ Twitter การกวาดนิ้วไปทางซ้ายแสดงตัวเลือก
Thomas Joulin

ใช่ฉันคิดเกี่ยวกับเรื่องนั้นดังนั้นถ้าฉันไม่สามารถทำได้ด้วยเหตุการณ์กดยาวฉันจะใช้วิธีการปัดนิ้ว แต่อาจมีบางคนในกองซ้อนล้นทำ ...
2010
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.