如何禁用UIPageViewController的滑动手势?

时间:2014-02-28 14:55:10

标签: ios uiviewcontroller uigesturerecognizer uipageviewcontroller

在我的情况下,父UIViewController包含UIPageViewController,其中包含UINavigationController,其中包含UIViewController。我需要向最后一个视图控制器添加滑动手势,但滑动处理就像它们属于页面视图控制器一样。我尝试以编程方式和通过xib执行此操作,但没有结果。

据我所知,在UIPageViewController处理手势之前我无法实现目标。如何解决这个问题?

22 个答案:

答案 0 :(得分:222)

阻止UIPageViewController滚动的文档化方法是不分配dataSource属性。如果您分配数据源,它将进入基于手势的'导航模式,这是您试图阻止的。

如果没有数据源,您可以使用setViewControllers:direction:animated:completion方法手动提供视图控制器,并且它将根据需要在视图控制器之间移动。

上述内容可以从Apple's documentation of UIPageViewController(概述,第二段)推断出来:

  

要支持基于手势的导航,您必须使用数据源对象提供视图控制器。

答案 1 :(得分:76)

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

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

        view.scrollEnabled = NO;
    }
}

答案 2 :(得分:45)

我将 user2159978 的回答翻译为 Swift

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

答案 3 :(得分:23)

将@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

答案 4 :(得分:9)

修改:此答案仅适用于页面卷曲样式。 Jessedc's answer要好得多:无论风格如何都有效,并且依赖记录的行为

UIPageViewController公开了它的手势识别器数组,你可以使用它来禁用它们:

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

答案 5 :(得分:4)

如果您希望UIPageViewController保持其滑动功能,同时允许您的内容控件使用其功能(滑动以删除等),只需关闭canCancelContentTouches即可UIPageViewController

将此内容放入UIPageViewController viewDidLoad个功能中。 (SWIFT)

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

UIPageViewController有一个自动生成的子视图,用于处理手势。我们可以阻止这些子视图取消内容手势。

...从

Swipe to delete on a tableView that is inside a pageViewController

答案 6 :(得分:4)

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
            }
        }
    }
}

答案 7 :(得分:2)

我解决了这个问题(Swift 4.1)

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

答案 8 :(得分:1)

与@ user3568340回答类似

Swift 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
        }
    }

答案 9 :(得分:1)

<div class="banner"> <div class="content"> <p>Testing Testing 1 2 3</p> <button id="playButton">Play Video</button> </div> </div> <div class="trailer" id="main"> <video id="mainvid" src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4" controls="true"></video> </div>

答案 10 :(得分:1)

我发现的答案对我来说很困惑或不完整,因此这里是一个完整且可配置的解决方案:

第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")
    }
}

答案 11 :(得分:0)

这是我的快速解决方案

extension UIPageViewController {
    var isScrollEnabled: Bool {
        set {
            (self.view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView)?.isScrollEnabled = newValue
        }
        get {
            return (self.view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView)?.isScrollEnabled ?? true
        }
    }
}

答案 12 :(得分:0)

如上所述,没有数据源是正确的答案。

这是我方便/快捷的Swift 5解决方案。

它基于以下事实:我的UIPageViewController子类还包含其dataSource。

print(m)
extension MyPagerVC: UIPageViewControllerDataSource {
    var isPagingEnabled:Bool {
        get { dataSource == nil ? false : true }
        set { dataSource = newValue ? self : nil }
    }
}

答案 13 :(得分:0)

有一种比大多数答案建议的方法简单得多的方法,即在nilviewControllerBefore数据源回调中返回viewControllerAfter

这将禁用iOS 11+设备上的滚动手势,同时保留使用dataSource的可能性(例如用于页面指示器的presentationIndex / presentationCount等)< / p>

它也禁用通过的导航。 iOS 11-13的pageControl(底部的点)。在iOS 14上,可以使用UIAppearance代理禁用底点导航。

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

答案 14 :(得分:0)

枚举子视图以找到UIPageViewController的scrollView对我不起作用,因为在页面控制器子类中找不到任何scrollView。因此,我想做的就是禁用手势识别器,但要小心以免禁用必要的手势识别器。

所以我想到了这个:

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

将其放在viewDidLoad()内,一切都准备就绪!

答案 15 :(得分:0)

@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
    }
}

答案 16 :(得分:0)

这样声明:

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

然后像这样使用它:

scrollView?.isScrollEnabled = true //false

答案 17 :(得分:0)

(Swift 4)您可以删除pageViewController的gestureRecognizers:

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

如果您更喜欢扩展名:

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

pageViewController.removeGestureRecognizers

答案 18 :(得分:0)

感谢@ user2159978的回答。

我让它更容易理解。

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

答案 19 :(得分:0)

翻译@ user2159978对C#的响应:

cv::Mat

答案 20 :(得分:-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%工作

答案 21 :(得分:-1)

只需在您的 UIPageViewController 子类中添加此控件属性:

var isScrollEnabled = true {
    didSet {
        for case let scrollView as UIScrollView in view.subviews {
            scrollView.isScrollEnabled = isScrollEnabled
        }
    }
}