programing

UITapGesture Recognizer가 있는 뷰 내부의 UIButton

powerit 2023. 5. 18. 21:31
반응형

UITapGesture Recognizer가 있는 뷰 내부의 UIButton

나는 볼 수 있습니다.UITapGestureRecognizer보기를 누르면 이 보기 위에 다른 보기가 나타납니다.이 새 보기에는 세 개의 단추가 있습니다.이 단추 중 하나를 누르면 단추 동작이 나타나지 않고 탭 동작만 나타납니다.그래서 저는 이 버튼들을 더 이상 사용할 수 없습니다.이 버튼으로 이벤트를 전달하려면 어떻게 해야 합니까?이상한 것은 버튼이 여전히 강조 표시된다는 것입니다.

UITapGesture Recognizer는 탭을 받은 후에만 제거할 수 없습니다.새 보기를 제거할 수도 있기 때문입니다.즉, 전체 화면 비디오 컨트롤과 같은 동작을 원합니다.

컨트롤러 또는 보기(동작 인식기를 생성하는 컨트롤러 또는 보기)를 의 대리자로 설정할 수 있습니다.UITapGestureRecognizer그런 다음 딜러에게 구현할 수 있습니다.-gestureRecognizer:shouldReceiveTouch:구현에서 터치가 새 하위 보기에 속하는지 테스트할 수 있으며, 해당되면 제스처 인식기에 무시하도록 지시할 수 있습니다.다음과 같은 것이 있습니다.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // test if our control subview is on-screen
    if (self.controlSubview.superview != nil) {
        if ([touch.view isDescendantOfView:self.controlSubview]) {
            // we touched our control surface
            return NO; // ignore the touch
        }
    }
    return YES; // handle the touch
}

Kevin Ballard의 답변에 대한 Casey의 후속 조치로서:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
        if ([touch.view isKindOfClass:[UIControl class]]) {
            // we touched a button, slider, or other UIControl
            return NO; // ignore the touch
        }
    return YES; // handle the touch
}

이것은 기본적으로 버튼, 슬라이더 등과 같은 모든 사용자 입력 유형의 컨트롤을 작동시킵니다.

다음 답변을 찾았습니다: 링크

사용할 수도 있습니다.

tapRecognizer.cancelsTouchesInView = NO;

그래서 탭 인식기가 모든 탭을 잡는 유일한 사람이 되는 것을 방지합니다.

업데이트 - Michael이 이 속성을 설명하는 문서에 대한 링크를 언급했습니다. 취소터치 인 뷰

Kevin Ballard의 답변에 대한 후속 조치로, 저는 이와 같은 문제를 겪었고 결국 이 코드를 사용하게 되었습니다.

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

동일한 효과를 제공하지만 모든 뷰 깊이의 UIButton에서 작동합니다(내 UIButton은 여러 뷰 깊이였고 UIGesture Recognizer의 대리자는 이에 대한 참조가 없었습니다).

iOS 6.0 이상에서는 기본 제어 동작이 제스처 인식기 동작의 중복을 방지합니다.예를 들어, 단추의 기본 작업은 한 번 탭입니다.단추의 상위 보기에 연결된 단일 탭 제스처 인식기가 있고 사용자가 단추를 누르면 단추의 동작 방법이 제스처 인식기 대신 터치 이벤트를 수신합니다.이는 다음을 포함하는 컨트롤의 기본 동작과 겹치는 제스처 인식에만 적용됩니다.

Apple의 API 문서에서

이 답변들은 불완전했습니다.저는 이 부울 연산을 사용하는 방법에 대해 여러 개의 게시물을 읽어야 했습니다.

*.h 파일에 이것을 추가합니다.

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

*.m 파일에 다음을 추가합니다.

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

    NSLog(@"went here ...");

    if ([touch.view isKindOfClass:[UIControl class]])
    {
        // we touched a button, slider, or other UIControl
        return NO; // ignore the touch
    }
    return YES; // handle the touch
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.



    //tap gestrure
    UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)];
    [tapGestRecog setNumberOfTapsRequired:1];
    [self.view addGestureRecognizer:tapGestRecog];


// This line is very important. if You don't add it then your boolean operation will never get called
tapGestRecog.delegate = self;

}


-(IBAction) screenTappedOnce
{
    NSLog(@"screenTappedOnce ...");

}

여기서 다른 방법을 찾았습니다.그것은 각 버튼 안에 있든 없든 터치를 감지합니다.

내부: 이벤트 포함: (2) 위치InView:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
       shouldReceiveTouch:(UITouch *)touch {
    // Don't recognize taps in the buttons
    return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] &&
            ![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] &&
            ![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]);
}

스위프트 5

탭 제스처가 있는 수퍼 뷰의 버튼

 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if let _ = touch.view as? UIButton { return false }
    return true
}

저의 경우 hitTest를 구현하는 것이 저에게 효과가 있었습니다.버튼이 있는 컬렉션 뷰가 있습니다.

이 메서드는 다음을 호출하여 보기 계층을 통과합니다.point(inside:with:)터치 이벤트를 수신할 서브뷰를 결정하는 각 서브뷰의 방법.한다면point(inside:with:)하는 가장 뷰의 가 유사하게 합니다. true를 반환합니다.

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard isUserInteractionEnabled else { return nil }

    guard !isHidden else { return nil }

    guard alpha >= 0.01 else { return nil }

    guard self.point(inside: point, with: event) else { return nil }

    for eachImageCell in collectionView.visibleCells {
        for eachImageButton in eachImageCell.subviews {
            if let crossButton = eachImageButton as? UIButton {
                if crossButton.point(inside: convert(point, to: crossButton), with: event) {
                    return crossButton
                }
            }
        }
    }
    return super.hitTest(point, with: event)
}

여기 제게 효과가 있었던 릴리 발라드의 스위프트 버전의 답변이 있습니다.

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (scrollView.superview != nil) {
        if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false }
    }
    return true
}

다음 부울을 설정하여 UITapGesture Recognizer가 다른 이벤트(예: 버튼 탭)를 취소하지 않도록 할 수 있습니다.

    [tapRecognizer setCancelsTouchesInView:NO];

시나리오가 다음과 같은 경우:

보기가 단순하고 UI 버튼이 몇 개 있습니다.해당 뷰에 하위 뷰로 추가된 UITextField 컨트롤.이제 컨트롤(추가한 하위 보기)을 제외한 보기의 다른 위치를 누르면 키보드가 해제됩니다.

솔루션은 다음과 같습니다.

다음 메서드를 XYZViewController.m(사용자의 보기가 있는)에 추가합니다.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}

cdasher의 대답을 최적화하는 것은, 당신은 이해합니다.

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

언급URL : https://stackoverflow.com/questions/3344341/uibutton-inside-a-view-that-has-a-uitapgesturerecognizer

반응형