UITapGestureRecognizer - แตะเพียงครั้งเดียวและแตะสองครั้ง


156

ฉันกำลังพยายามเพิ่ม 2 UITapGestureRecognizersในมุมมองหนึ่งรายการสำหรับการแตะครั้งเดียวและอีกอันสำหรับกิจกรรมการแตะสองครั้ง ตัวจำแนกแท็ปเดียวทำงานตามที่คาดไว้ (ด้วยตัวมันเอง) แต่ดูเหมือนว่าฉันจะไม่สามารถทำให้ตัวจำแนกลายมือ Tap ทำงานได้

ได้พยายามที่จะทดลองกับคุณสมบัติที่ต้องการ: cancelsTouchesInView, delaysTouchesBeganและdelaysTouchesEndedแต่ก็ยังไม่ได้ทำงาน

เมื่อฉันแตะสองครั้งตัวจำแนกการแตะเดียวจะเปิดใช้งานเสมอและเหตุการณ์การแตะสองครั้งก็จะถูกส่งไปยังมุมมองระดับสูง แต่ตัวจดจำการแตะสองครั้งที่กำหนดเองดูเหมือนจะไม่ได้รับการแจ้งเตือนเลย

เอกสารดูเหมือนจะแนะนำว่า 3 คุณสมบัติที่กล่าวถึงข้างต้นสามารถนำมาใช้เพื่อวัตถุประสงค์ แต่ฉันไม่แน่ใจว่าควรตั้งค่าใดและควรใช้ตัวจำแนกลายมือใด (เดี่ยวสองหรือสอง) หวังว่าคนที่คุ้นเคยกับสิ่งนี้จะช่วยได้

ต่อไปนี้เป็นบล็อกรหัสที่อัพเดทล่าสุด

// ****** gesture recognizers ******

- (void)addSingleAndDoubleTapGestureRecognizersToView:(UIView *)view
{
    // single tap    
    UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector(handleSingleTapOnView:)];                                 
    [singleTapRecognizer setNumberOfTouchesRequired:1];
    [view addGestureRecognizer: singleTapRecognizer];

    // double tap 
    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector (handleDoubleTapOnView:)];        
    [doubleTapRecognizer setNumberOfTouchesRequired:2];         
    [singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
    [view addGestureRecognizer: doubleTapRecognizer];         
}

- (void)handleSingleTapOnView:(id)sender
{

}

- (void)handleDoubleTapOnView:(id)sender
{

}

30
ความคิดเห็นแบบสุ่ม: ขีดล่างในชื่อตัวแปรจะทำให้โปรแกรมเมอร์ส่วนใหญ่ Objective-C ประจบประแจง สิ่งที่แย่กว่านั้นคือชื่อตัวแปรของคุณไม่ได้อธิบาย ทำไมไม่เพียงใช้ singleTapRecognizer และ doubleTapRecognizer (หรือบางอย่างที่คล้ายกัน) ใช้เวลาพิมพ์น้อยกว่าในการแยก แต่ทำให้โค้ดของคุณอ่านง่ายขึ้น
UIAdam

ขอบคุณสำหรับคำแนะนำเห็นด้วยกับคุณว่าชื่อตัวแปรควรเป็นคำอธิบายเพิ่มเติม แต่ส่วนรหัสเฉพาะนี้ยังไม่ได้รับการสรุปและจะโพสต์รหัสที่ขัดเกลาและมีความหมายมากขึ้นตามที่แนะนำ ...
Stanley

ในกรณีที่คนอื่นมีปัญหาคล้ายกัน ฉันพยายามที่จะรับการแตะสองครั้งและตัวจดจำการแตะเดียวทำงานร่วมกันอย่างรวดเร็ว (การแตะครั้งเดียวทำงานได้ดี แต่ไม่มีการแตะสองครั้ง) ฉันลากตัวจดจำไปยังฉากโดยใช้กระดานเรื่องราว ฉันมีตัวจัดการและคำสั่ง: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) ภายใน viewDidLoad ของฉัน แต่ก็ยังไม่มีการแตะสองครั้ง ชิ้นส่วนปริศนาที่ขาดหายไปของฉันคือการลากไอคอนตัวจำแนกการแตะสองครั้ง (จากแถวบนสุดของฉาก) เหนือส่วนของมุมมองที่จะต้องจดจำการแตะสองครั้ง
พอลลัส

1
@UIAdam ใช้เครื่องหมายขีดล่างเพื่อใส่คำนำหน้าชื่อ ivar ส่วนตัวใน objc นั้นเป็นเรื่องปกติ (มาจากพื้นหลังที่รวดเร็ว)
Charlton Provatas

คำตอบ:


412
UITapGestureRecognizer *singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSingleTap)] autorelease];
singleTap.numberOfTapsRequired = 1; 
[self.view addGestureRecognizer:singleTap];

UITapGestureRecognizer *doubleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doDoubleTap)] autorelease];
doubleTap.numberOfTapsRequired = 2; 
[self.view addGestureRecognizer:doubleTap];

[singleTap requireGestureRecognizerToFail:doubleTap];

หมายเหตุ: หากคุณกำลังใช้งานอยู่ numberOfTouchesRequired จะต้องมี .numberOfTouchesRequired = 1;

สำหรับสวิฟท์

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didPressPartButton))
singleTapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.require(toFail: doubleTapGesture)

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

ฉันสามารถมีไฟล์การใช้งานของคุณสำหรับสิ่งนี้ได้ไหม
Anil Kothari

@Stanley: คำตอบ Anils ควรทำงานนอกหลักสูตรคุณยังต้องเตรียมการจัดการ (doSingleTap, doDoubleTap)
Rok Jarc

การแตะครั้งเดียวจะอัปเดต UITableView ซึ่งทำงานได้ตามที่คาดไว้ การแตะสองครั้งในขณะนี้เพียงแค่พิมพ์คำสั่งบันทึกโดยใช้ NSLog ความสงสัยของฉันคือสถานะการตอบกลับแรกไปจาก UIView ไปยังที่อื่นหลังจากแตะครั้งแรกเนื่องจากฉันไม่ได้ทำสิ่งใดอย่างชัดเจนเกี่ยวกับห่วงโซ่การตอบสนอง
สแตนลี่ย์

6
วิธีแก้ปัญหาใช้งานได้สำหรับฉัน ตัวเลือกการแตะเดี่ยวจะเริ่มทำงานหลังจากผ่านไประยะเวลาหนึ่ง
Vladimir Obrizan

46

โซลูชัน Swift 3:

let singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTap)

let doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTap)

singleTap.require(toFail: doubleTap)

ในโค้ดบรรทัดsingleTap.require (toFail: doubleTap)เรากำลังบังคับให้แตะครั้งเดียวเพื่อรอและตรวจสอบให้แน่ใจว่าเหตุการณ์การแตะไม่ใช่การแตะสองครั้ง


31

คุณต้องใช้เมธอด requireGestureRecognizerToFail: บางสิ่งเช่นนี้

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


ได้ลองใช้การเรียกเมธอด "ล้มเหลว" กับตัวจดจำทั้งสองทันทีแล้ว แต่ก็ยังใช้งานไม่ได้ หากคุณเคยแตะสองครั้งก่อนหน้านี้โปรดแบ่งปันประสบการณ์ของคุณกับฉัน
สแตนลีย์

1
ฉันได้ลองใช้รหัสที่แน่นอนนี้ (เช่นเดียวกับที่ Anil โพสต์ในรายละเอียดเพิ่มเติม) และใช้งานได้สำหรับฉัน
UIAdam

ขอบคุณสำหรับความคิดเห็นแล้วยังคงต้องมีบางอย่างที่พลาดในส่วนของฉันฉัน ...
สแตนเลย์

รหัสของคุณยังคงยุ่งอยู่กับความล่าช้าแตะและอะไร ทำให้เป็นไปตามรหัสของ Anil ใช้ onlyGestureRecognizerToFail เพียงครั้งเดียวที่เรามี
UIAdam

จะทำตามที่คุณแนะนำในวันนี้หรือพรุ่งนี้ในขณะที่ฉันหมดเวลาชั่วครู่ ขอขอบคุณสำหรับความช่วยเหลือชนิดของคุณ ...
สแตนเลย์

15

// ---- ก่อนอื่นคุณต้องจัดสรรท่าทางแตะสองครั้งและครั้งเดียว ------- //

UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleDoubleTap:)];

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleSingleTap:)];

[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];

// ----------------------- จำนวนการแตะ ---------------- //

[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];

// ------- เพิ่มการแตะสองครั้งและการแตะเพียงครั้งเดียวบนมุมมองหรือปุ่ม -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];

10

ไม่แน่ใจว่าเป็นสิ่งที่คุณกำลังมองหา แต่ฉันทำก๊อกเดี่ยว / คู่โดยไม่ต้องจดจำท่าทาง ฉันใช้มันใน UITableView ดังนั้นฉันใช้รหัสนั้นในวิธี didSelectRowAtIndexPath

    tapCount++;
    switch (tapCount)
    {
        case 1: //single tap
            [self performSelector:@selector(singleTap:) withObject: indexPath afterDelay: 0.2];
            break;
        case 2: //double tap
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap:) object:indexPath];
            [self performSelector:@selector(doubleTap:) withObject: indexPath];
            break;
        default:
            break;
    }
    if (tapCount>2) tapCount=0;

วิธีการ singleTap และ doubleTap เป็นเพียงโมฆะกับ NSIndexPath เป็นพารามิเตอร์:

- (void)singleTap:(NSIndexPath *)indexPath {
  //do your stuff for a single tap
}

- (void)doubleTap:(NSIndexPath *)indexPath {
  //do your stuff for a double tap
}

หวังว่ามันจะช่วย


ขอบคุณสำหรับคำตอบ @Nargarg คุณมีปัญหาเกี่ยวกับตัวจำแนกลายมือ doubleTap หรือไม่?
สแตนลี่ย์

@Stanley ไม่ singleTap กำลังรอ 0.2 วินาทีก่อนยิง และถ้าในเวลาเดียวกันการเปิดใช้งานการแตะครั้งที่สองวิธี singleTap จะถูกยกเลิก
Novarg

มันดูมีแนวโน้มมากขอบคุณสำหรับความช่วยเหลือของคุณ ฉันหมดเวลาแล้ววันนี้อีกครั้ง จะให้มันลองในวันพรุ่งนี้แน่นอน :)
Stanley

คำตอบที่สร้างสรรค์;)
Michael

ทางออกที่ดีมาก ฉันแค่ต้องเพิ่ม tapCount = 0 ในแต่ละ handler (singleTap, doubleTap) เพื่อให้แน่ใจว่าการสัมผัสต่อไปนี้ได้รับการยอมรับเช่นกัน
Sirio

3

โซลูชันสำหรับ Swift 2:

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTapGesture.numberOfTapsRequired = 1 // Optional for single tap
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)

1

ฉันใช้วิธี UIGestureRecognizerDelegate เพื่อตรวจจับทั้ง singleTap และ doubleTap

เพิ่งทำสิ่งนี้

 UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTapGesture:)];
    [doubleTap setDelegate:self];
    doubleTap.numberOfTapsRequired = 2;
    [self.headerView addGestureRecognizer:doubleTap];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleTapGesture:)];
    singleTap.numberOfTapsRequired = 1;
    [singleTap setDelegate:self];
    [doubleTap setDelaysTouchesBegan:YES];
    [singleTap setDelaysTouchesBegan:YES];
    [singleTap requireGestureRecognizerToFail:doubleTap];
    [self.headerView addGestureRecognizer:singleTap];

จากนั้นใช้วิธีการมอบหมายเหล่านี้

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return  YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

0

บางมุมมองมีตัวจดจำการแตะสองครั้งในตัว ( MKMapViewเป็นตัวอย่าง) ในการหลีกเลี่ยงปัญหานี้คุณจะต้องใช้UIGestureRecognizerDelegateวิธีshouldRecognizeSimultaneouslyWithGestureRecognizerและผลตอบแทนYES:

ก่อนอื่นให้ใช้ตัวจดจำคู่และเดี่ยวของคุณ:

// setup gesture recognizers
UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(mapViewTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;


UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                      action:@selector(mapViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;    // this allows
doubleTapRecognizer.numberOfTapsRequired = 2;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

จากนั้นใช้:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }

-1

ในการอ้างอิงถึงความคิดเห็นของ @ stanley -

อย่าพยายามใช้ท่าทางสัมผัสเพื่อเลือกแถวเพื่อทำงานUITableViewเนื่องจากมีการจัดการแทปแบบเต็มแล้ว ....

แต่คุณต้องตั้งค่า 'ยกเลิกการสัมผัสในมุมมอง' เป็น 'ไม่' ในโปรแกรมรู้จำท่าทางการแตะครั้งเดียวของคุณหรือจะไม่เคยได้รับเหตุการณ์การแตะ

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