UIPageViewController의 스 와이프 동작을 어떻게 비활성화합니까?


125

내 경우에는 부모 UIViewControllerUIPageViewController포함 UINavigationController하는 포함 UIViewController합니다. 마지막 뷰 컨트롤러에 스 와이프 제스처를 추가해야하지만 스 와이프는 마치 페이지 뷰 컨트롤러에 속하는 것처럼 처리됩니다. 프로그래밍 방식과 xib를 통해이 작업을 시도했지만 결과는 없습니다.

내가 이해하는 것처럼 UIPageViewController제스처를 처리 할 때까지 목표를 달성 할 수 없습니다 . 이 문제를 해결하는 방법?


7
사용pageViewControllerObject.view.userInteractionEnabled = NO;
Srikanth

6
모든 내용을 차단하기 때문에 잘못되었습니다. 그러나 제스처 만 차단해야합니다.
user2159978

왜 이런 짓을하는? 앱에서 어떤 행동을 원하십니까? 아키텍처를 너무 복잡하게 만드는 것처럼 들립니다. 어떤 행동을하는지 설명 할 수 있습니까?
Fogmeister

의 페이지 중 하나에가 UIPageViewController있습니다 UINavigationController. 고객이 스 와이프 제스처로 탐색 컨트롤러를 팝업하려고하지만 (가능한 경우) 페이지보기 컨트롤러가 스 와이프를 대신 처리
user2159978

@Srikanth 감사합니다, 그것이 바로 내가 필요한 것입니다! 프로그래밍 방식으로 페이지 변경을 트리거하고 누군가가 스 와이프하여 페이지 변경을 중단했을 때 내 페이지보기가 중단되었으므로 코드에서 페이지 변경이 트리거 될 때마다 일시적으로 스 와이프를 비활성화해야합니다 ...
Kuba Suder

답변:


262

UIPageViewController스크롤 을 방지하는 문서화 된 방법 은 dataSource속성을 할당하지 않는 것 입니다. 데이터 소스를 할당하면이를 방지하려는 '제스처 기반'탐색 모드로 이동합니다.

데이터 소스가없는 경우 setViewControllers:direction:animated:completion방법 을 원할 때 수동으로 뷰 컨트롤러를 제공하면 필요 에 따라 뷰 컨트롤러간에 이동할 수 있습니다.

위의 내용은 Apple의 UIPageViewController 문서 (개요, 두 번째 단락) 에서 추론 할 수 있습니다 .

제스처 기반 탐색을 지원하려면 데이터 소스 객체를 사용하여 뷰 컨트롤러를 제공해야합니다.


1
이 솔루션도 선호합니다. 이전 데이터 소스를 변수에 저장하고 데이터 소스를 nil로 설정 한 다음 이전 데이터 소스를 복원하여 스크롤을 다시 활성화 할 수 있습니다. 모든 것이 깨끗하지는 않지만 기본보기 계층을 통과하여 스크롤보기를 찾는 것보다 훨씬 좋습니다.
Matt R

3
데이터 소스를 비활성화하면 텍스트 필드 하위보기에 대한 키보드 알림에 대한 응답으로 문제가 발생합니다. UIScrollView를 찾기 위해 뷰의 하위 뷰를 반복하는 것이 더 안정적인 것으로 보입니다.
AR Younce

9
화면 하단의 점이 제거되지 않습니까? 그리고 스 와이프가없고 점이 없으면 PageViewController를 전혀 사용하지 않아도됩니다. 나는 asker가 점을 유지하기를 원한다고 생각합니다.
Leo Flaherty

이것은 페이지가 비동기 적으로로드되고 사용자가 스 와이프 제스처를 만들 때 직면했던 문제를 해결하는 데 도움이되었습니다. 브라보 :)
Ja͢ck

1
A. R Younce가 맞습니다. 키보드 알림에 대한 응답으로 PageViewController의 데이터 소스를 비활성화하는 경우 (예 : 키보드를 켰을 때 사용자가 가로로 스크롤하지 않게하려면) PageViewController의 데이터 소스를 제외하면 키보드가 즉시 사라집니다.
micnguyen

82
for (UIScrollView *view in self.pageViewController.view.subviews) {

    if ([view isKindOfClass:[UIScrollView class]]) {

        view.scrollEnabled = NO;
    }
}

5
이것은 페이지 제어를 유지합니다.
Marcus Adams

1
페이지 컨트롤 (작은 점)을 유지하기 때문에 훌륭한 접근 방법입니다. 페이지를 수동으로 변경할 때 업데이트하려고합니다. 이 stackoverflow.com/a/28356383/1071899
Simon Bøgh

1
왜 안돼for (UIView *view in self.pageViewController.view.subviews) {
dengApro

사용자는 왼쪽 및 오른쪽 절반의 페이지 컨트롤을 탭하여 페이지 간을 계속 탐색 할 수 있습니다.
MasterCarl

57

user2159978의 답변 을 Swift 5.1로 번역합니다.

func removeSwipeGesture(){
    for view in self.pageViewController!.view.subviews {
        if let subView = view as? UIScrollView {
            subView.isScrollEnabled = false
        }
    }
}

30

@lee (@ user2159978) 솔루션을 확장으로 구현 :

extension UIPageViewController {
    var isPagingEnabled: Bool {
        get {
            var isEnabled: Bool = true
            for view in view.subviews {
                if let subView = view as? UIScrollView {
                    isEnabled = subView.isScrollEnabled
                }
            }
            return isEnabled
        }
        set {
            for view in view.subviews {
                if let subView = view as? UIScrollView {
                    subView.isScrollEnabled = newValue
                }
            }
        }
    }
}

사용법 : (에서 UIPageViewController)

self.isPagingEnabled = false

더 우아하게하기 위해 다음과 같이 추가 할 수 있습니다. var scrollView: UIScrollView? { for view in view.subviews { if let subView = view as? UIScrollView { return subView } } return nil }
Wagner Sales

여기서 게터는 마지막 하위 뷰의 활성화 된 상태 만 반환합니다.
앤드류 던컨

8

나는 이것을 잠시 동안 싸워 왔고 Jessedc의 대답에 따라 해결책을 게시해야한다고 생각했다. PageViewController의 데이터 소스를 제거합니다.

내 PgeViewController 클래스에이를 추가 (스토리 보드에 내 페이지 뷰 컨트롤러에 연결, 상속 둘 UIPageViewControllerUIPageViewControllerDataSource) :

static func enable(enable: Bool){
    let appDelegate  = UIApplication.sharedApplication().delegate as! AppDelegate
    let pageViewController = appDelegate.window!.rootViewController as! PgeViewController
    if (enable){
        pageViewController.dataSource = pageViewController
    }else{
        pageViewController.dataSource = nil
    }
}

그런 다음 각 하위 뷰가 나타날 때 호출 할 수 있습니다 (이 경우 비활성화).

override func viewDidAppear(animated: Bool) {
    PgeViewController.enable(false)
}

나는 이것이 누군가를 도울 수 있기를 희망합니다.

편집 : 누군가 이것을 Objective-C로 번역하려면 :)


8

편집 :이 답변은 페이지 말림 스타일에만 적용됩니다. Jessedc의 대답 은 훨씬 낫습니다. 스타일에 관계없이 작동하며 문서화 된 동작에 의존합니다 .

UIPageViewController 동작 인식기 배열을 표시하며이를 사용하지 않도록 설정할 수 있습니다.

// myPageViewController is your UIPageViewController instance
for (UIGestureRecognizer *recognizer in myPageViewController.gestureRecognizers) {
    recognizer.enabled = NO;
}

8
코드를 테스트 했습니까? myPageViewController.gestureRecognizers는 항상 비어 있습니다.
user2159978

11
이 솔루션은 페이지 컬 스타일을 위해 작동하는 것 같다,하지만 내 응용 프로그램에서 나는 스크롤 뷰 스타일의 사용
user2159978

8
가로 스크롤에서 작동하지 않습니다. 반환 된 값은 항상 빈 배열입니다.
Khanh Nguyen

스크롤 스타일로 이것을 알아 냈습니까?
Esqarrouth

4

당신이 원하는 경우 UIPageViewController콘텐츠 컨트롤이 자신의 기능을 (문지 삭제 등)에 사용할 수 있도록하면서, 슬쩍 그것의 기능을 유지 단지 끕니다 canCancelContentTouchesUIPageViewController.

이것을 당신 UIPageViewControllerviewDidLoad기능 에 넣으십시오 . (빠른)

if let myView = view?.subviews.first as? UIScrollView {
    myView.canCancelContentTouches = false
}

UIPageViewController제스처를 처리하는 자동 생성 된 하위보기가 있습니다. 이러한 서브 뷰가 컨텐츠 제스처를 취소하지 못하게 할 수 있습니다.

에서...

pageViewController 안에있는 tableView에서 스 와이프하여 삭제


카터 감사합니다. 귀하의 솔루션을 시도했습니다. 그러나 여전히 pageViewController가 하위 테이블보기에서 가로 스 와이프 조치를 초과하는 경우가 있습니다. 사용자가 자식 테이블보기를 스 와이프 할 때 제스처를 먼저 얻기 위해 항상 테이블보기의 우선 순위를 지정하려면 어떻게해야합니까?
David Liu

3

UIPageViewController스 와이프를 활성화 및 비활성화 하는 유용한 확장 기능입니다 .

extension UIPageViewController {

    func enableSwipeGesture() {
        for view in self.view.subviews {
            if let subView = view as? UIScrollView {
                subView.isScrollEnabled = true
            }
        }
    }

    func disableSwipeGesture() {
        for view in self.view.subviews {
            if let subView = view as? UIScrollView {
                subView.isScrollEnabled = false
            }
        }
    }
}

3

나는 이것을 이렇게 해결했다 (Swift 4.1)

if let scrollView = self.view.subviews.filter({$0.isKind(of: UIScrollView.self)}).first as? UIScrollView {
             scrollView.isScrollEnabled = false
}

3

@lee 답변의 깔끔한 방법

extension UIPageViewController {
    var isPagingEnabled: Bool {
        get {
            return scrollView?.isScrollEnabled ?? false
        }
        set {
            scrollView?.isScrollEnabled = newValue
        }
    }

    var scrollView: UIScrollView? {
        return view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView
    }
}

0

@ user3568340와 비슷한 답변

스위프트 4

private var _enabled = true
    public var enabled:Bool {
        set {
            if _enabled != newValue {
                _enabled = newValue
                if _enabled {
                    dataSource = self
                }
                else{
                    dataSource = nil
                }
            }
        }
        get {
            return _enabled
        }
    }

0

@ user2159978의 답변에 감사드립니다.

좀 더 이해하기 쉽게 만듭니다.

- (void)disableScroll{
    for (UIView *view in self.pageViewController.view.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
            UIScrollView * aView = (UIScrollView *)view;
            aView.scrollEnabled = NO;
        }
    }
}

0

내가 찾은 답변은 매우 혼란 스럽거나 불완전한 것처럼 보이므로 여기에는 완전하고 구성 가능한 솔루션이 있습니다.

1 단계:

왼쪽 및 오른쪽 스크롤이 활성화되어 있는지 여부를 알려주는 각 PVC 요소에 책임을 부여하십시오.

protocol PageViewControllerElement: class {
    var isLeftScrollEnabled: Bool { get }
    var isRightScrollEnabled: Bool { get }
}
extension PageViewControllerElement {
    // scroll is enabled in both directions by default
    var isLeftScrollEnabled: Bool {
        get {
            return true
        }
    }

    var isRightScrollEnabled: Bool {
        get {
            return true
        }
    }
}

각 PVC 뷰 컨트롤러는 위의 프로토콜을 구현해야합니다.

2 단계:

PVC 컨트롤러에서 필요한 경우 스크롤을 비활성화하십시오.

extension SomeViewController: PageViewControllerElement {
    var isRightScrollEnabled: Bool {
        get {
            return false
        }
    }
}

class SomeViewController: UIViewController {
    // ...    
}

3 단계 :

PVC에 효과적인 스크롤 잠금 방법을 추가하십시오.

class PVC: UIPageViewController, UIPageViewDelegate {
    private var isLeftScrollEnabled = true
    private var isRightScrollEnabled = true
    // ...

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...
        self.delegate = self
        self.scrollView?.delegate = self
    }
} 

extension PVC: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("contentOffset = \(scrollView.contentOffset.x)")

        if !self.isLeftScrollEnabled {
            disableLeftScroll(scrollView)
        }
        if !self.isRightScrollEnabled {
            disableRightScroll(scrollView)
        }
    }

    private func disableLeftScroll(_ scrollView: UIScrollView) {
        let screenWidth = UIScreen.main.bounds.width
        if scrollView.contentOffset.x < screenWidth {
            scrollView.setContentOffset(CGPoint(x: screenWidth, y: 0), animated: false)
        }
    }

    private func disableRightScroll(_ scrollView: UIScrollView) {
        let screenWidth = UIScreen.main.bounds.width
        if scrollView.contentOffset.x > screenWidth {
            scrollView.setContentOffset(CGPoint(x: screenWidth, y: 0), animated: false)
        }
    }
}

extension UIPageViewController {
    var scrollView: UIScrollView? {
        return view.subviews.filter { $0 is UIScrollView }.first as? UIScrollView
    }
}

4 단계 :

새 화면에 도달 할 때 스크롤 관련 속성을 업데이트합니다 (일부 화면으로 전환하는 경우 enableScroll 메서드를 호출하는 것을 잊지 마십시오).

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    let pageContentViewController = pageViewController.viewControllers![0]
    // ...

    self.enableScroll(for: pageContentViewController)
}

private func enableScroll(for viewController: UIViewController) {
    guard let viewController = viewController as? PageViewControllerElement else {
        self.isLeftScrollEnabled = true
        self.isRightScrollEnabled = true
        return
    }

    self.isLeftScrollEnabled = viewController.isLeftScrollEnabled
    self.isRightScrollEnabled = viewController.isRightScrollEnabled

    if !self.isLeftScrollEnabled {
        print("Left Scroll Disabled")
    }
    if !self.isRightScrollEnabled {
        print("Right Scroll Disabled")
    }
}

0

반환하는 것입니다 대부분의 해답이 여기 제안보다 훨씬 간단한 방법,있다 nilviewControllerBeforeviewControllerAfter는 dataSource 콜백.

이렇게하면 iOS 11+ 기기에서 스크롤 동작이 비활성화되고 페이지 표시에 사용 dataSourcepresentationIndex/ 와 같은 항목 을 사용할 수 있습니다.presentationCount

또한 탐색을 비활성화합니다. pageControl(하단의 도트)

extension MyPageViewController: UIPageViewControllerDataSource {
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        return nil
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        return nil
    }
}

0

pageViewController.view.isUserInteractionEnabled = false


-1

C #에 대한 @ user2159978의 응답 번역 :

foreach (var view in pageViewController.View.Subviews){
   var subView = view as UIScrollView;
   if (subView != null){
     subView.ScrollEnabled = enabled;
   }
}

-1

(Swift 4) pageViewController의 gestureRecognizer를 제거 할 수 있습니다.

pageViewController.view.gestureRecognizers?.forEach({ (gesture) in
            pageViewController.view.removeGestureRecognizer(gesture)
        })

확장을 선호하는 경우 :

extension UIViewController{
    func removeGestureRecognizers(){
        view.gestureRecognizers?.forEach({ (gesture) in
            view.removeGestureRecognizer(gesture)
        })
    }
}

pageViewController.removeGestureRecognizers


-1

다음과 같이 선언하십시오.

private var scrollView: UIScrollView? {
    return pageViewController.view.subviews.compactMap { $0 as? UIScrollView }.first
}

그런 다음 다음과 같이 사용하십시오.

scrollView?.isScrollEnabled = true //false

-1

UIPageViewController내 페이지 컨트롤러 하위 클래스에서 scrollView를 찾을 수 없으므로 서브 뷰를 열거하여 scrollView를 찾지 못했습니다. 그래서 내가 생각한 것은 동작 인식기를 비활성화하는 것이지만 필요한 인식기를 비활성화하지 않도록 조심해야합니다.

그래서 나는 이것을 생각해 냈습니다.

if let panGesture = self.gestureRecognizers.filter({$0.isKind(of: UIPanGestureRecognizer.self)}).first           
    panGesture.isEnabled = false        
}

그것을 안에 넣고 viewDidLoad()모두 설정했습니다!


-1
 override func viewDidLayoutSubviews() {
    for View in self.view.subviews{
        if View.isKind(of: UIScrollView.self){
            let ScrollV = View as! UIScrollView
            ScrollV.isScrollEnabled = false
        }

    }
}

이것을 pageviewcontroller 클래스에 추가하십시오. 100 % 일


이 코드를 직면하고 발행 어떤 코멘트 완벽하게 작동하십시오 : /
ap00724

-1

이 컨트롤 속성을 UIPageViewController 서브 클래스에 추가하십시오 .

var isScrollEnabled = true {
    didSet {
        for case let scrollView as UIScrollView in view.subviews {
            scrollView.isScrollEnabled = isScrollEnabled
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.