UITapGestureRecognizer แบ่ง UITableView didSelectRowAtIndexPath


207

ฉันได้เขียนฟังก์ชั่นของตัวเองเพื่อเลื่อนฟิลด์ข้อความเมื่อคีย์บอร์ดปรากฏขึ้น เพื่อที่จะยกเลิกคีย์บอร์ดโดยการแตะออกจากช่องข้อความฉันได้สร้างสิ่งUITapGestureRecognizerที่ดูแลการลาออกจากการตอบกลับครั้งแรกในช่องข้อความเมื่อแตะไป

ตอนนี้ฉันได้สร้างการเติมข้อความอัตโนมัติให้กับUITableViewฟิลด์ข้อความที่สร้างฟิลด์ข้อความด้านล่างและเติมด้วยรายการที่ผู้ใช้ป้อนข้อความ

อย่างไรก็ตามเมื่อเลือกหนึ่งในรายการในตาราง auto เสร็จแล้วdidSelectRowAtIndexPathจะไม่ถูกเรียก แต่ดูเหมือนว่าตัวจดจำท่าทางแตะกำลังถูกเรียกใช้และเพิ่งลาออกจากการตอบกลับก่อน

ฉันเดาว่ามีวิธีที่จะบอกให้รู้จำท่าทางการแตะเพื่อส่งข้อความแตะต่อไปUITableViewเรื่อย ๆ แต่ฉันไม่สามารถเข้าใจได้ว่ามันคืออะไร ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมมาก


คำตอบ:


258

ตกลงในที่สุดก็พบว่าหลังจากการค้นหาผ่านเอกสารจำแนกลายมือ

วิธีแก้ไขคือการนำไปใช้UIGestureRecognizerDelegateและเพิ่มสิ่งต่อไปนี้:

////////////////////////////////////////////////////////////
// UIGestureRecognizerDelegate methods

#pragma mark UIGestureRecognizerDelegate methods

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isDescendantOfView:autocompleteTableView]) {

        // Don't let selections of auto-complete entries fire the 
        // gesture recognizer
        return NO;
    }

    return YES;
}

ที่ดูแลมัน หวังว่านี่จะช่วยผู้อื่นเช่นกัน


คุณต้องข้ามก๊อกบนช่องข้อความด้วย
Steven Kramer

5
ฉันมีโชคมากขึ้นด้วยreturn ![touch.view isKindOfClass:[UITableViewCell class]];
Josh Paradroid

1
@Josh วิธีนี้ใช้ไม่ได้หากคุณแตะที่ป้ายด้านในเซลล์ จริงๆแล้วคำตอบของ Jason นั้นสมบูรณ์แบบสำหรับสิ่งที่ฉันต้องการ
William T.

แต่นี่ไม่ใช่คำตอบสำหรับปัญหาของคุณใช่ไหม? นี่คือ / หรือ โดยพื้นฐานแล้วการสัมผัสใด ๆ ในมุมมองตารางนั้นไม่มีความสำคัญกับตัวรู้จำท่าทาง ... สิ่งที่คุณต้องการคือทั้งตัวรู้จำท่าทางและการเลือกมุมมองตารางให้ทำงาน
PostCodeism

5
@Durgaprasad หากต้องการปิดใช้งานตัวจดจำรูปแบบลายเส้นอย่างชัดเจนเมื่อเลือกเซลล์ที่ฉันเพิ่มไว้ ![touch.view isEqual: self.tableView] &&ก่อนหน้านี้[touch.view isDescendantOfView: self.tableView]เพื่อแยกtableViewตัวเอง (เพราะisDescendantOfView:จะส่งกลับYESเช่นกันหากอาร์กิวเมนต์มุมมองเป็นตัวรับมุมมองตัวเอง) หวังว่าจะช่วยคนอื่นที่ต้องการผลลัพธ์เหมือนกัน
anneblue

220

วิธีที่ง่ายที่สุดในการแก้ปัญหานี้คือ:

UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] 
    initWithTarget:self action:@selector(tap:)];
[tapRec setCancelsTouchesInView:NO];

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

นอกจากนี้การขยายคำตอบของ Robert ถ้าคุณมีตัวชี้ไปยัง tableview ในคำถามคุณสามารถเปรียบเทียบ class ได้โดยตรงแทนที่จะต้องแปลงเป็น string และหวังว่า Apple จะไม่เปลี่ยนชื่อ:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
     shouldReceiveTouch:(UITouch *)touch
{
    if([touch.view class] == tableview.class){
        return //YES/NO
    }

    return //YES/NO

}

โปรดจำไว้ว่าคุณต้องประกาศUIGestureRecognizerให้มีตัวแทนด้วยรหัสนี้


4
ขอบคุณ setCancelsTouchesInView ทุกอย่างเปลี่ยนแปลง :)
PostCodeism

อาจยังต้องการใช้isDescendantOfViewแทนการตรวจสอบว่าclassเท่ากันเนื่องจากคุณอาจแตะที่ subview ขึ้นอยู่กับสิ่งที่คุณต้องการ
ชิม

71

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

ตัวอย่างเช่น swift

let tapOnScreen: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "CheckTheTime")
tapOnScreen.cancelsTouchesInView = false
view.addGestureRecognizer(tapOnScreen)

1
ขอบคุณมากสำหรับสิ่งนี้!
Bishan

1
นี่คือความสะอาดที่สุดในสวิฟท์ ขอบคุณ
Dx_

ทำงานได้ดีภายในเซลล์ใน tableview น่ารักและเรียบง่าย!
Abdoelrhman

@laoyur จริงมาก
bLacK hoLE

ยังคงได้รับการคลิกจากเซลล์แทนท่าทางแตะ
famfamfam

42

และสำหรับ Swift (อิงจากคำตอบจาก @Jason):

class MyAwesomeClass: UIViewController, UIGestureRecognizerDelegate

private var tap: UITapGestureRecognizer!

override func viewDidLoad() {
   super.viewDidLoad()

   self.tap = UITapGestureRecognizer(target: self, action: "viewTapped:")
   self.tap.delegate = self
   self.view.addGestureRecognizer(self.tap)
}

// UIGestureRecognizerDelegate method
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if touch.view?.isDescendantOfView(self.tableView) == true {
        return false
    }
    return true
}

ขอบคุณมากที่ช่วยประหยัดเวลาของฉัน
Bishan

22

ฉันอาจมีวิธีแก้ปัญหาที่ดีกว่าในการเพิ่มท่าทางแตะผ่านมุมมองตาราง แต่อนุญาตให้เลือกเซลล์ได้ในเวลาเดียวกัน:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if gestureRecognizer is UITapGestureRecognizer {
        let location = touch.locationInView(tableView)
        return (tableView.indexPathForRowAtPoint(location) == nil)
    }
    return true
}

ฉันแค่มองหาเซลล์ที่จุดของหน้าจอที่ผู้ใช้กำลังแตะ หากไม่พบเส้นทางของดัชนีฉันจะปล่อยให้ท่าทางรับสัมผัสมิฉะนั้นฉันจะยกเลิก สำหรับฉันมันใช้งานได้ดี


1
วิธีการแก้ปัญหานี้หิน! มีประโยชน์มากที่จะแยกแยะเซลล์ออกจากเขตข้อมูลที่ว่างของตาราง ..
Alessandro Ornano

18

ผมคิดว่ามีความจำเป็นต้องเขียนบล็อกของรหัสเพียงแค่ตั้งไม่มี cancelsTouchesInViewการfalseสำหรับวัตถุท่าทางของคุณโดยการเริ่มต้นมันและคุณเพียงแค่ต้องตั้งมันtrue falseหากคุณใช้UITapGestureวัตถุในรหัสของคุณและใช้UIScrollView(tableview, collectionview) จากนั้นตั้งค่าคุณสมบัตินี้false

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)

ขอบคุณสำหรับการโพสต์คำตอบนี้
Gustavo Baiocchi Costa

14

วิธีแก้ไขปัญหาที่คล้ายคลึงกันคือการนำไปใช้gestureRecognizer:shouldReceiveTouch:โดยใช้คลาสของมุมมองเพื่อพิจารณาว่าควรดำเนินการอย่างไร วิธีนี้มีข้อดีของการไม่ปิดบังก๊อกในพื้นที่รอบ ๆ ตารางโดยตรง (มุมมองของพื้นที่เหล่านี้ยังคงสืบทอดมาจากอินสแตนซ์ UITableView แต่ไม่ได้แสดงถึงเซลล์)

นอกจากนี้ยังมีโบนัสที่สามารถใช้งานได้กับหลายตารางในมุมมองเดียว (โดยไม่ต้องเพิ่มรหัสเพิ่มเติม)

Caveat: มีข้อสันนิษฐานว่า Apple จะไม่เปลี่ยน classname

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return ![NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"];
}

1
หากต้องการกำจัดสตริงของชื่อคลาสให้ใช้บรรทัดนี้return ![[touch.view.superview class] isSubclassOfClass:[UITableViewCell class]];
Nianliang

7

สำหรับSwift 4.2วิธีแก้ไขคือการนำไปใช้UIGestureRecognizerDelegateและเพิ่มสิ่งต่อไปนี้:

extension ViewController : UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view!.isDescendant(of: tblView) {
            return false
        }
        return true
    }
}

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


1
ขอบคุณเพื่อนที่โพสต์คำตอบนี้คุณประหยัดเวลาของฉัน
Jay Bhalani

4

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

รหัสผลลัพธ์คือการรวมกันของคำตอบของ Abdulrahman Masoud และคำตอบของ Nikolaj Nielsen

extension MyViewController: UIGestureRecognizerDelegate {
    func addGestureRecognizer() {
        let tapOnScreen = UITapGestureRecognizer(target: self,
                                                action: #selector(functionToCallWhenUserTapsOutsideOfTableView))

        // stop the gesture recognizer from "consuming" the touch event, 
        // so that the touch event can reach other buttons on view.
        tapOnScreen.cancelsTouchesInView = false

        tapOnScreen.delegate = self

        self.view.addGestureRecognizer(tapOnScreen)
    }

    // if your tap event is on the menu, don't run the touch event.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view?.isDescendant(of: self.tableView) == true {
            return false
        }
        return true
    }

    @objc func functionToCallWhenUserTapsOutsideOfTableView() {

        print("user tapped outside table view")
    }
}

และในMyViewControllerชั้นเรียนชั้นเรียนที่มีUITableViewในonViewDidLoad()ฉันทำให้แน่ใจว่าจะโทรaddGestureRecognizer():

class MyViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        self.addGestureRecognizer()
        ...
    }
    ...
}

3

เพียงแค่ตั้งค่าcancels touches in viewเพื่อfalseท่าทางใด ๆ ที่อยู่ภายใต้(table/collection)View:

- อินเตอร์เฟสผู้สร้าง

InterfaceBuilder

- รหัส

<#gestureRecognizer#>.cancelsTouchesInView = false

จะทำอย่างไรถ้าฉันต้องการปิดการใช้งานมันไม่เพียง แต่จะทำให้ didSelectRowAt ทำงานได้เท่านั้น
Eyad Shokry

1

ในขณะที่มันสายและหลายคนพบว่าคำแนะนำข้างต้นทำงานได้ดีฉันไม่สามารถใช้วิธีของ Jason หรือ TMilligan ได้

ฉันมีTableView แบบสแตติกที่มีหลายเซลล์ที่มี textFields ที่รับอินพุตจำนวนเข้าโดยใช้แป้นพิมพ์ตัวเลขเท่านั้น นี่เหมาะสำหรับฉัน:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if(![touch.view isKindOfClass:[UITableViewCell class]]){

        [self.firstTF resignFirstResponder];
        [self.secondTF resignFirstResponder];
        [self.thirdTF resignFirstResponder];
        [self.fourthTF resignFirstResponder];

        NSLog(@"Touches Work ");

        return NO;
    }
    return YES;
}

ตรวจสอบให้แน่ใจว่าคุณได้ใช้สิ่งนี้<UIGestureRecognizerDelegate>ในไฟล์. h ของคุณ

บรรทัดนี้![touch.view isKindOfClass:[UITableViewCell class]]ตรวจสอบว่า tableViewCell ถูกแตะและยกเลิกคีย์บอร์ดที่ใช้งานอยู่หรือไม่


1

วิธีแก้ปัญหาง่ายๆคือการใช้อินสแตนซ์ UIControl ใน UITableViewCell เพื่อรับการสัมผัส คุณสามารถเพิ่มมุมมองใด ๆ ด้วย userInteractionEnables == NO ไปยัง UIControl เพื่อรับการแตะ


0

นี่คือวิธีแก้ปัญหาของฉันซึ่งเชื่อมโยงโดยตรงกับตัวจดจำของตัวจดจำโดยตรงกับว่าแป้นพิมพ์กำลังแสดงอยู่หรือไม่

ในผู้รับมอบสิทธิ์จำแนกท่าทางแตะของคุณ:

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([PFXKeyboardStateListener sharedInstance].visible) {
        return YES;
    }

    return NO;
}

และPFXKeyboardStateListener.h:

@interface PFXKeyboardStateListener : NSObject
{
    BOOL _isVisible;
}

+ (PFXKeyboardStateListener *)sharedInstance;

@property (nonatomic, readonly, getter=isVisible) BOOL visible;

@end

และPFXKeyboardStateListener.m:

static PFXKeyboardStateListener *sharedInstance;

@implementation PFXKeyboardStateListener

+ (PFXKeyboardStateListener *)sharedInstance
{
    return sharedInstance;
}

+ (void)load
{
    @autoreleasepool {
        sharedInstance = [[self alloc] init];
    }
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (BOOL)isVisible
{
    return _isVisible;
}

- (void)didShow
{
    _isVisible = YES;
}

- (void)didHide
{
    _isVisible = NO;
}

- (id)init
{
    if ((self = [super init])) {
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil];
    }
    return self;
}

@end

คุณอาจต้องการอัพเดทรูปแบบซิงเกิลของฟังคีย์บอร์ดฉันยังไม่ได้ฟังเลย หวังว่านี่จะใช้ได้กับทุกคนเช่นเดียวกับที่ใช้ได้กับฉัน ^^


0

ใช้วิธีนี้สำหรับผู้รับมอบสิทธิ์ของ UIGestureRecognizer:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch
{
  UIView *superview = touch.view;
  do {
    superview = superview.superview;
    if ([superview isKindOfClass:[UITableViewCell class]])
      return NO;
  } while (superview && ![superview isKindOfClass:[UITableView class]]);

  return superview != nil;
}

0

อย่างรวดเร็วคุณสามารถใช้สิ่งนี้ภายใน

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if CheckTheTime() == true {
        // do something 
    }else{
    }
}

func CheckTheTime() -> Bool{
    return true
}

0

กรณีของฉันแตกต่างกันรวมถึง uisearchbar และ uitableview บน self.view ฉันต้องการยกเลิกแป้นพิมพ์ uisearchbar โดยแตะที่มุมมอง

var tapGestureRecognizer:UITapGestureRecognizer?

override func viewWillAppear(animated: Bool) {
    tapGestureRecognizer = UITapGestureRecognizer(target: self, action:Selector("handleTap:"))
}

ในวิธีการมอบหมาย UISearchBar:

func searchBarShouldBeginEditing(searchBar: UISearchBar) -> Bool {
    view.addGestureRecognizer(tapGestureRecognizer!)
    return true
}
func searchBarShouldEndEditing(searchBar: UISearchBar) -> Bool {
    view.removeGestureRecognizer(tapGestureRecognizer!)
    return true
}

เมื่อผู้ใช้สัมผัสกับ self.view:

func handleTap(recognizer: UITapGestureRecognizer) {
    sampleSearchBar.endEditing(true)
    sampleSearchBar.resignFirstResponder()
}

0

สวิฟต์ 5, พฤษภาคม 2563

ฉันมี textField และ tableView ที่มองเห็นได้เมื่อฉันป้อนข้อความ

สถานะเริ่มต้น ดังนั้นฉันต้องการกิจกรรม 2 เหตุการณ์ที่แตกต่างกันเมื่อฉันแตะ tableViewCell หรืออย่างอื่น

กำลังแสดงแป้นพิมพ์และ tableView

ก่อนอื่นเราจะเพิ่ม tapGestureRecognizer

tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
tap.delegate = self
view.addGestureRecognizer(tap)

@objc func viewTapped() {
        view.endEditing(true)
}

จากนั้นเราจะเพิ่มการตรวจสอบต่อไปนี้ใน UIGestureRecognizerDelegate:

extension StadtViewController: UIGestureRecognizerDelegate {

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view?.isDescendant(of: self.tableView) == true {
        return false
    } else {
        view.endEditing(true)
        return true
    }
}

}

หากฉันต้องการซ่อนแป้นพิมพ์ก่อน tableView จะยังคงปรากฏให้เห็นและตอบสนองกับก๊อกของฉัน

ป้อนคำอธิบายรูปภาพที่นี่


-1

นี่คือคำตอบของฉันตามคำตอบข้างต้น ... มันใช้ได้กับฉัน ...

//Create tap gesture for menu transparent view
UITapGestureRecognizer *rightTableTransparentViewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rightTableTransparentViewTapMethod:)];
[rightTableTransparentViewTap setCancelsTouchesInView:NO];
[_rightTableTransparentView addGestureRecognizer:rightTableTransparentViewTap];

- (void)rightTableTransparentViewTapMethod:(UITapGestureRecognizer *)recognizer {
    //Write your code here
}

-1

ประเด็นปัญหา: ในกรณีของฉันปัญหาคือเดิมฉันวางปุ่มในแต่ละคอลเลกชันดูและตั้งข้อ จำกัด ในการเติมเซลล์ดังนั้นเมื่อคลิกเซลล์มันจะคลิกปุ่ม แต่ฟังก์ชั่นปุ่มว่างเปล่าดังนั้นไม่มีอะไรเลย ดูเหมือนจะเกิดขึ้น

การแก้ไข: ฉันแก้ไขสิ่งนี้โดยลบปุ่มออกจากเซลล์มุมมองคอลเล็กชัน

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