如何禁用UIPageViewController的滑动手势?

149
在我的情况下,父级UIViewController 包含UIPageViewController ,后者包含UINavigationController ,后者又包含UIViewController。 我需要在最后一个视图控制器中添加一个滑动手势,但是滑动手势被处理得好像它们属于页面视图控制器一样。 我尝试通过编程和xib来实现此操作,但没有任何结果。
因此,我理解的是,在UIPageViewController处理其手势之前,我无法实现我的目标。如何解决这个问题?

9
使用 pageViewControllerObject.view.userInteractionEnabled = NO;,将页面视图控制器对象的用户交互功能设置为禁用。 - Srikanth
9
不正确,因为它也会阻挡所有内容。但我只需要阻止它的手势。 - user2159978
你为什么要这样做?你希望应用程序有什么行为表现?听起来你正在过度复杂化架构。你能解释一下你想要的行为表现吗? - Fogmeister
1
UIPageViewController 中的一个页面包含 UINavigationController。客户希望在滑动手势时弹出导航控制器(如果可能的话),但是页面视图控制器处理滑动手势。 - user2159978
1
@Srikanth 谢谢,这正是我需要的!当我以编程方式触发页面更改并有人用手指滑动打断时,我的页面视图会崩溃,所以我不得不在代码中每次触发页面更改时暂时禁用滑动... - Kuba Suder
显示剩余2条评论
25个回答

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 视图控制器都应该实现上述协议。
第二步:
在您的 PVC 控制器中,如有需要请禁用滚动:
extension SomeViewController: PageViewControllerElement {
    var isRightScrollEnabled: Bool {
        get {
            return false
        }
    }
}

class SomeViewController: UIViewController {
    // ...    
}

第三步:

向您的 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
func removeSwipeGesture(){
    for view in self.pageViewController!.view.subviews {
        if let subView = view as? UIScrollView {
            subView.isScrollEnabled = false
        }
    }

}

假设您已经单独创建了pageControl,并与pagecontroller适当地进行了链接。
private let pageControl = PageControl()
pageControl.delegate = self
pageControl.numberOfPages = pages.count
pageControl.addTarget ....

如果你想隐藏那个单点,因为你的数据源没有其他视图控制器了,你可以像这样禁用它。
pageControl.hidesForSinglePage = true

-1

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

所以我想到了这个:

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

将其放入viewDidLoad()中,一切都准备就绪!

-1

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

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

-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类中。百分之百有效。


请评论一下您遇到的问题,这段代码完美运行 :/ - Pathak Ayush

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接