ProgramingTip

UIPageViewController 제스처 인식기

bestdevel 2021. 1. 10. 22:58
반응형

UIPageViewController 제스처 인식기


한동안 신청서 작업을 해왔지만 NDA 때문에이 질문을 할 수 없습니다.

내 Viewcontroller에 UIPageViewController로드가 있습니다. 뷰 컨트롤러에는 PageViewControllers 제스처 인식기에 의해 재정의되는 버튼이 있습니다. 예를 들어 뷰 컨트롤러의 오른쪽에 버튼이 있고 PageViewController가 페이지를 넘겨 받아 변경합니다.

PageViewController에서 버튼이 터치를 수신하고 제스처를 취소해야 할 일을 인식합니까?

PageViewController가 내 ViewController를 뷰의 하위 뷰로 저렴하게 생각합니다.

모든 제스처를 끌 수 있다고 생각합니다.

나는 이 클래스가 하위 클래스가 아니라고 사과가 말했듯이 PageViewController를 하위 클래스로 지정하지 않는 것을 선호합니다 .


재정의 할 수 있습니다.

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

PageViewController가 터치를 수신하지 않고 수신해야하는시기를 더 잘 제어합니다. Dev API Gesture Recognizers의 "터치 분석에서 제스처 인식기 방지"를 사용합니다.

내 솔루션은 UIPageViewController의 RootViewController에서 다음과 달라집니다.

viewDidLoad에서 :

//EDITED Need to take care of all gestureRecogizers. Got a bug when only setting the delegate for Tap
for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
    gR.delegate = self;
}

재정의 :

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    //Touch gestures below top bar should not make the page turn.
    //EDITED Check for only Tap here instead.
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        CGPoint touchPoint = [touch locationInView:self.view];
        if (touchPoint.y > 40) {
            return NO;
        }
        else if (touchPoint.x > 50 && touchPoint.x < 430) {//Let the buttons in the middle of the top bar receive the touch
            return NO;
        }
    }
    return YES;
}

그리고 RootViewController를 UIGestureRecognizerDelegate로 설정하는 것을 잊지 마세요.

(참고로, 저는 가로 모드에만 있습니다.)

편집-위의 코드는 Swift 2로 번역되었습니다.

viewDidLoad에서 :

for gr in self.view.gestureRecognizers! {
    gr.delegate = self
}

보기 컨트롤러가 페이지 상속되도록 UIGestureRecognizerDelegate만들고 다음을 추가합니다.

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if let _ = gestureRecognizer as? UITapGestureRecognizer {
        let touchPoint = touch .locationInView(self.view)
        if (touchPoint.y > 40 ){
            return false
        }else{
            return true
        }
    }
    return true
}

다음은 Xcode 템플릿 viewDidLoadself.view.gestureRecognizers = self.pageViewController.gestureRecognizers파트 바로 가기 템플릿에 추가 할 수있는 또 다른 솔루션 입니다. 제스처 인식기의 내장을 엉망으로 만들거나 대리인을 처리하지 않습니다. 보기에서 탭 제스처 인식기를 제거하고 스 와이프 인식기 만 남깁니다.

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

// Find the tap gesture recognizer so we can remove it!
UIGestureRecognizer* tapRecognizer = nil;    
for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) {
    if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
        tapRecognizer = recognizer;
        break;
    }
}

if ( tapRecognizer ) {
    [self.view removeGestureRecognizer:tapRecognizer];
    [self.pageViewController.view removeGestureRecognizer:tapRecognizer];
}

이제 페이지 사이를 전환 할 경우 와이프해야합니다. 탭은 이제 페이지보기 상단의 컨트롤에서만 작동합니다.


나는 같은 문제가 있었다. 샘플 및 문서는 loadView 또는 viewDidLoad에서이를 수행합니다.

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

이 UIViewControllers 뷰의 제스처 인식이 UIPageViewController의 gestureRecognizers로 대체됩니다. 이제 터치가 발생하면 먼저 pageViewController 제스처 인식기를 통해 전송됩니다. 일치하지 하위보기로 전송됩니다.

해당 줄의 주석 처리를 제거하면 모든 것이 예상대로 작동합니다.

필립


ios6에서 작동하지 않는 것 같이 gestureRecognizers 대리 튼 viewController로 설정하면 더 이상 ios6에서 작동하지 않습니다.

for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
    gR.delegate = self;
}

iOS6에서 pageViewController의 gestureRecognizers 대리 튼튼 viewController로 설정하면 충돌이 발생합니다.


최신 버전 (iOS 8.1 이상을 대상으로하는 Xcode 7.3에 있음)에서는 솔루션이 작동하지 않는 것입니다.

허용되는 답변은 오류와 함께 충돌합니다.

UIScrollView의 기본 제공 이동 동작 인식기에는 스크롤 뷰가 델리게이트로 표시됩니다.

현재 가장 높은 순위의 답변 (Pat McG에서 제공)은 더 이상 작동하지 않습니다. UIPageViewController의 scrollview가 확인할 수없는 이상한 제스처 인식기 하위 클래스를 사용하는 것 같기 때문 입니다. 따라서 문이 실행되지 if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] )않습니다.

각 인식기에서 TouchesInView를 false로 설정하여 하위보기도 UIPageViewController터치를받을 있습니다.

에서 viewDidLoad:

guard let recognizers = self.pageViewController.view.subviews[0].gestureRecognizers else {
    print("No gesture recognizers on scrollview.")
    return
}

for recognizer in recognizers {
    recognizer.cancelsTouchesInView = false
}

나는 사용했다

for (UIScrollView *view in _pageViewController.view.subviews) {
    if ([view isKindOfClass:[UIScrollView class]]) {
        view.delaysContentTouches = NO;
    }
}

클릭이 UIPageViewController 내부의 버튼을 통과하도록 허용


제 경우에는 UIPageControl에서 탭핑을하고 화면의 다른 버튼으로 탭핑을 받도록 지원합니다. 스 와이프는 여전히 작동합니다. 나는 여러 가지 방법을 시도하는 가장 간단한 작업 솔루션이라고 생각합니다.

for (UIPageControl *view in _pageController.view.subviews) {
    if ([view isKindOfClass:[UIPageControl class]]) {
        view.enabled = NO;
    }
}

이것은 UIPageController 하위보기에서 UIPageControl을 가져오고 사용자 상호 작용을보고합니다.


서브 클래 싱 한 버튼을 사용하는 경우 touchesBegan, touchesMoved 및 touchesEnded를 재정적으로 적절한 프로그래밍 방식으로 페이지 전환을 호출하지만 수퍼를 호출하지 않고 터치를 알림 체인에 호출 할 수 있습니다.


또한 사용할 수 있습니다. (도움을 주셔서 감사합니다.)

// add UIGestureRecognizerDelegate

NSPredicate *tp = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [UITapGestureRecognizer class]];
UITapGestureRecognizer *tgr = (UITapGestureRecognizer *)[self.pageViewController.view.gestureRecognizers filteredArrayUsingPredicate:tp][0];
tgr.delegate = self; // tap delegating

NSPredicate *pp = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [UIPanGestureRecognizer class]];
UIPanGestureRecognizer *pgr = (UIPanGestureRecognizer *)[self.pageViewController.view.gestureRecognizers filteredArrayUsingPredicate:pp][0];
pgr.delegate = self; // pan delegating

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{
    CGPoint touchPoint = [touch locationInView:self.view];

    if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) && touchPoint.y > 915 ) {
        return NO; // if y > 915 px in portrait mode
    }

    if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && touchPoint.y > 680 ) {
        return NO; // if y > 680 px in landscape mode
    }

    return YES;
}

나를 위해 완벽하게 작동 :)


이것은 나를 위해 가장 잘 작동 한 솔루션입니다 .JRAMER 답변을 시도했지만 경계를 넘어서 페이징 할 때 오류가 발생하는 것을 제외하고는 괜찮습니다 (페이지 -1 또는 23 페이지).

PatMCG 솔루션은 모든 탭 인식기를 취소하기 때문에 제공하지. 저는 여전히 탭을 원했지만 레이블되지 않았습니다.

내 UILabel에서 다음과 같이 간단하게 썼습니다.이 취소 된 탭은 내 레이블에만 해당됩니다.

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
 if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
     return NO;
 } else {
     return YES;
 }
}

사용자가 다양한 페이지 뷰로 점프, 컬 및 슬라이드 할 때 많은 사람들로 pageviewcontroller를 만듭니다. 새로운 pageviewcontroller를 만드는 루틴 위에는 우수한 코드의 약간 더 간단한 버전을 사용합니다.

UIPageViewController *npVC = [[UIPageViewController alloc]
                       initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
                       navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
                       options: options];
...

// Find the pageView tap gesture recognizer so we can remove it!
for (UIGestureRecognizer* recognizer in npVC.gestureRecognizers) {
    if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
        UIGestureRecognizer* tapRecognizer = recognizer;
        [npVC.view removeGestureRecognizer:tapRecognizer];
       break;
    }
}

이제 탭이 원하는대로 작동합니다 (왼쪽 및 오른쪽 탭이 페이지를 점프하고 컬이 잘 작동합니다.


RootViewController에서 하위보기 (새 IBOutlet gesturesView에 연결됨)를 만들고이 새보기에 제스처를 할당하기 만하면됩니다. 이보기는 제스처를 활성화하려는 화면 부분을 포함합니다.

viewDidLoad 변경 :

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

받는 사람 :

self.gesturesView.gestureRecognizers = self.pageViewController.gestureRecognizers;

탭 인식기 제거를위한 Swift 3 확장 :

    import UIKit

extension UIPageViewController {
    func removeTapRecognizer() {
        let gestureRecognizers = self.gestureRecognizers

        var tapGesture: UIGestureRecognizer?
        gestureRecognizers.forEach { recognizer in
            if recognizer.isKind(of: UITapGestureRecognizer.self) {
                tapGesture = recognizer
            }
        }
        if let tapGesture = tapGesture {
            self.view.removeGestureRecognizer(tapGesture)
        }
    }
}

UIPageViewController 내에서 자식 뷰 컨트롤러의 탭에 응답하는 간단하고 포괄적 인 방법을 찾는 동안 여기에 왔습니다. 내 솔루션의 핵심 (Swift 4, Xcode 9)은 내 RootViewController.swift(Xcode의 "페이지 기반 앱"템플릿과 동일한 구조) 에서 다음과 같이 간단 해졌습니다 .

override func viewDidLoad() {
    super.viewDidLoad()

    ...

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(pageTapped(sender:)))
    self.pageViewController?.view.subviews[0].addGestureRecognizer(tapGesture)
}

...

@objc func pageTapped(sender: UITapGestureRecognizer) {
    print("pageTapped")
}

(또한 실제로 탭한 페이지, 즉 현재 페이지를 추적 할 수 있도록 이 답변사용했습니다 .)


나는 작동하는 해결책을 찾았다. UIPageViewController에 다른 UIGestureRecognizer를 추가하고 아래 제공된 delegate 메서드를 구현합니다. 어떤 제스처를 잠 그거나 더 전달해야하는지 확인해야하는 매 순간마다이 메서드가 호출됩니다. 에 대한 참조를 제공하는 것을 잊지 confictingView마십시오. 제 경우에는 이동 제스처도 인식하는 UITableView였습니다. 이 뷰는 UIPageViewController 내에 배치되었으므로 이동 제스처가 두 번 또는 무작위로 인식되었습니다. 이제이 메서드에서 팬 제스처가 내 UITableView와 UIPageViewController 내에 있는지 확인하고 UIPanGestureRecognizer가 기본이라고 결정합니다.

이 접근 방식은 다른 제스처 인식기를 직접 재정의하지 않으므로 언급 된 'NSInvalidArgumentException'에 대해 걱정할 필요가 없습니다.

패턴은 실제로 Apple에서 승인하지 않습니다. :)

 var conflictingView:UIView?
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if otherGestureRecognizer.view === pageViewController?.view {

            if let view = conflictingView {
                var point = otherGestureRecognizer.location(in: self.view)
                if view.frame.contains(point) {
                    print("Touch in conflicting view")
                    return false
                }
            }
            print("Touch outside conficting view")
            return true
        }
        print("Another view passed out")
        return true
    }

참조 URL : https://stackoverflow.com/questions/7788780/uipageviewcontroller-gesture-recognizers

반응형