[objective-c] UIGestureRecognizer는 터치 이벤트 처리를 위해 하위보기를 차단합니다.

나는 이것이 어떻게 올바른 방법으로 수행되는지 알아 내려고 노력하고 있습니다. 나는 상황을 묘사하려고 노력했습니다.
여기에 이미지 설명 입력

UITableView하위 뷰로 추가 하고 UIView있습니다. UIView있는 누르고 응답 pinchGestureRecognizer하지만, 이렇게이 때 상기의 tableview 그 두 제스처에 반응이 중지 (여전히 와이프 반응).

다음 코드로 작동하도록 만들었지 만 분명히 좋은 솔루션이 아니며 더 나은 방법이 있다고 확신합니다. 이것은 UIView(Superview)에 있습니다.

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if([super hitTest:point withEvent:event] == self) {
        for (id gesture in self.gestureRecognizers) {
            [gesture setEnabled:YES];
        }
        return self;
    }
    for (id gesture in self.gestureRecognizers) {
        [gesture setEnabled:NO];
    }
    return [self.subviews lastObject];
}



답변

나는 매우 유사한 문제가 있었고이 질문에서 내 해결책 찾았습니다 . 요약하면, 자신을 대리인으로 설정 UIGestureRecognizer한 다음 인식기가 터치를 처리하도록 허용하기 전에 대상보기를 확인하십시오. 관련 위임 방법은 다음과 같습니다.

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


답변

하위보기에 대한 터치 이벤트 차단이 기본 동작입니다. 이 동작을 변경할 수 있습니다.

UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];


답변

자체 테이블 뷰가있는 드롭 다운 하위 뷰를 표시하고있었습니다. 결과적으로 touch.view는 때때로 UITableViewCell. 나는 그것이 내가 생각했던 서브 클래스인지 확인하기 위해 수퍼 클래스 (들)를 밟아야했다.

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    UIView *view = touch.view;
    while (view.class != UIView.class) {
        // Check if superclass is of type dropdown
        if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own
            NSLog(@"Is of type dropdown; returning NO");
            return NO;
        } else {
            view = view.superview;
        }
    }

    return YES;
}


답변

@Pin Shih Wang 답변을 구축하십시오 . 탭 제스처 인식기가 포함 된보기의 탭을 제외한 모든 탭은 무시됩니다. 모든 탭은 설정 한대로 정상적으로보기 계층으로 전달됩니다 tapGestureRecognizer.cancelsTouchesInView = false. 다음은 Swift3 / 4의 코드입니다.

func ensureBackgroundTapDismissesKeyboard() {
    let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
    tapGestureRecognizer.cancelsTouchesInView = false
    self.view.addGestureRecognizer(tapGestureRecognizer)
}

@objc func handleTap(recognizer: UIGestureRecognizer) {
    let location = recognizer.location(in: self.view)
    let hitTestView = self.view.hitTest(location, with: UIEvent())
    if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) {
        // I dismiss the keyboard on a tap on the scroll view
        // REPLACE with own logic
        self.view.endEditing(true)
    }
}


답변

한 가지 가능성은 제스처 인식기를 하위 클래스로 분류하고 (아직하지 않은 경우) 재정 의하여 -touchesBegan:withEvent:각 터치가 제외 된 하위보기에서 시작되었는지 여부를 결정 -ignoreTouch:forEvent:하고 그 경우 해당 터치를 호출 하도록 재정의 하는 것 입니다.

분명히 제외 된 하위보기 또는 제외 된 하위보기의 배열을 추적하려면 속성도 추가해야합니다.


답변

어떤 클래스도 상속하지 않고 할 수 있습니다.

제스처의 콜백 선택기에서 gestureRecognizers를 확인할 수 있습니다.

view.gestureRecognizers에 gestureRecognizer가 포함되어 있지 않으면 무시하십시오.

예를 들면

- (void)viewDidLoad
{
    UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self     action:@selector(handleSingleTap:)];
    singleTapGesture.numberOfTapsRequired = 1;
}

여기에서 view.gestureRecognizers 확인

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
    UIEvent *event = [[UIEvent alloc] init];
    CGPoint location = [gestureRecognizer locationInView:self.view];

    //check actually view you hit via hitTest
    UIView *view = [self.view hitTest:location withEvent:event];

    if ([view.gestureRecognizers containsObject:gestureRecognizer]) {
        //your UIView
        //do something
    }
    else {
        //your UITableView or some thing else...
        //ignore
    }
}


답변

특정 뷰의 수퍼 뷰에 연결된 모든 제스처 인식기를 차단하도록 설계된 UIGestureRecognizer 하위 클래스를 만들었습니다.

내 WEPopover 프로젝트의 일부입니다. 여기에서 찾을 수 있습니다 .