Trình nhận dạng cử chỉ và hành động của nút


99

Tôi có một hệ thống phân cấp chế độ xem trông giống như sau:

UIView (A)
UIView > UIImageView
UIView > UIView (B)
UIView > UIView (B) > Rounded Rect Button
UIView > UIView (B) > UIImageView
UIView > UIView (B) > UILabel

Tôi đã đính kèm (các) trình nhận dạng cử chỉ vào UIView (B) của mình. Vấn đề mà tôi đang gặp phải là tôi không nhận được bất kỳ hành động nào đối với Nút Hình chữ nhật tròn nằm bên trong UIView (B). Trình nhận dạng cử chỉ SingleTap sẽ ghi lại / ghi đè sự kiện Touch Up Inside của nút.

Làm thế nào tôi có thể làm cho nó hoạt động? Tôi nghĩ rằng hệ thống phân cấp chuỗi phản hồi sẽ đảm bảo rằng sự kiện chạm vào nút sẽ được ưu tiên và nó SẼ được kích hoạt! Tôi đang thiếu cái gì?

Đây là một số mã liên quan:

#pragma mark -
#pragma mark View lifecycle (Gesture recognizer setup)

- (void)viewDidLoad {
    [super viewDidLoad];

    // double tap gesture recognizer
    UITapGestureRecognizer *dtapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGestureRecognizer:)];
    dtapGestureRecognize.delegate = self;
    dtapGestureRecognize.numberOfTapsRequired = 2;
    [self.viewB addGestureRecognizer:dtapGestureRecognize];

    // single tap gesture recognizer
    UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestureRecognizer:)];
    tapGestureRecognize.delegate = self;
    tapGestureRecognize.numberOfTapsRequired = 1;
    [tapGestureRecognize requireGestureRecognizerToFail:dtapGestureRecognize];
    [self.viewB addGestureRecognizer:tapGestureRecognize];

    // add gesture recodgnizer to the grid view to start the edit mode
    UILongPressGestureRecognizer *pahGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognizerStateChanged:)];
    pahGestureRecognizer.delegate = self;
    pahGestureRecognizer.minimumPressDuration = 0.5;
    [self.viewB addGestureRecognizer:pahGestureRecognizer];

    [dtapGestureRecognize release];
    [tapGestureRecognize release];
    [pahGestureRecognizer release];
}

#pragma mark -
#pragma mark Button actions

- (IBAction)buttonTouchUpInside:(id)sender {
    NSLog(@"%s, %@", __FUNCTION__, sender);
}

#pragma mark -
#pragma mark Gesture recognizer actions


- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)doubleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)longPressGestureRecognizerStateChanged:(UIGestureRecognizer *)gestureRecognizer {

    switch (gestureRecognizer.state) {

        case UIGestureRecognizerStateEnded: {
            NSLog(@"%s", __FUNCTION__);

            break;
        }
        default:
            break;
    }
}

Cách đơn giản nhất là để thiết lập cancelsTouchesInView = false
Bagusflyer

Câu trả lời:


176

Trong phương thức "shouldReceiveTouch", bạn nên thêm một điều kiện sẽ trả về KHÔNG nếu cảm ứng đang ở trong nút.

Đây là từ ví dụ SimpleGestureRecognizers của apple .

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

    // Disallow recognition of tap gestures in the segmented control.
    if ((touch.view == yourButton)) {//change it to your condition
        return NO;
    }
    return YES;
}

hy vọng nó sẽ giúp

Biên tập

Như Daniel đã lưu ý, bạn phải tuân theo để UIGestureRecognizerDelegatenó hoạt động.

shani


1
Ah!!! Có, tôi đã quên về phương thức -gestureRecognizer: shouldReceiveTouch: này. Cám ơn đã chỉ tôi hướng đi đúng. Mặc dù điều này giải quyết được vấn đề của tôi, nhưng tôi vẫn không biết tại sao hệ thống phân cấp người trả lời không hoạt động trong trường hợp này. Nó có thể nên, nhưng nó không được Apple xử lý.
Mustafa

2
Hành vi của UIGestureRecognizer được mô tả rõ ràng là tách biệt với chuỗi phản hồi "bình thường". Đây là một quyết định thiết kế của Apple.
Sylvain G.

11
Hãy nhớ tuân thủ Giao thức UIGestureRecognizerDelegate và đặt đại biểu của UIGestureRecognizer cho đối tượng đó.
Daniel

2
Để sử dụng rộng rãi hơn, hãy xem xét một số biến thể trong các điều khoản kiểm tra của Ramesh hoặc flypig. Ví dụ: trong trường hợp của tôi, tôi đã kết thúc bằng dòng: if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {... Lưu ý rằng các ô trong tableview được "chạm" vào contentView của chúng, là một thành viên của lớp private, vì vậy thay vào đó chúng tôi sẽ kiểm tra lớp của superview.
clozach

Cảm ơn bạn đã trả lời! Trong trường hợp của tôi, tôi đã gặp phải vấn đề tương tự nhưng tôi chỉ phát hiện ra nó cho đến khi tôi kiểm tra trên thiết bị thực tế. Chạy ứng dụng trong trình mô phỏng mà không sử dụng UIGestureDelegate như được chỉ ra trong câu trả lời này đã hoạt động như mong đợi mặc dù không chính xác.
Luis Artola

51

Tôi cũng gặp vấn đề tương tự, sau đó tôi đã thử với

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

    if ([touch.view isKindOfClass:[UIButton class]]) {      //change it to your condition
        return NO;
    }
    return YES;
}

Nó đang hoạt động hoàn hảo .........


4
tôi chỉ bỏ lỡmyGestureRecognizer.delegate = self;
zero3nna

20

Nói chung, chúng tôi sử dụng phương pháp ủy quyền dưới đây để tránh đụng chạm trong tất cả các loại UIControls:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if (([touch.view isKindOfClass:[UIControl class]])) {
         return NO;
    }
    return YES;
}

Lưu ý: KHÔNG thực hiện việc kiểm tra này (kiểm tra loại lớp Recogzer.view), cử chỉ này sẽ không hoạt động.


11

Đây là phiên bản Swift 3.0 :

extension UIViewController: UIGestureRecognizerDelegate {

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view is UIButton {
        return false
    }
    return true
}

Đừng quên:

Make your tapper object delegate to self (e.g: tapper.delegate = self)


6

Đây là một phiên bản Swift:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (touch.view!.isKindOfClass(UIButton)) {
        return false
    }
    return true
}

Đừng quên:

  1. Làm cho lớp bạn tuân theo UIGestureRecognizerDelegate
  2. Đặt đối tượng tapper của bạn ủy quyền cho chính mình (ví dụ tapper.delegate = self:)

5

Giải pháp tốt nhất cho tôi là sử dụng đoạn mã dưới đây:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
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.