如何仅针对横向禁用 UIPageViewController 的分页?

How to disable paging of UIPageViewController only for landscape orientation?

我有一个 scroll 过渡样式 UIPageViewController 需要仅在设备处于横向时禁用分页。但是分页应该在纵向启用。

我在 SO 中遇到过类似的问题,但不是我的特定需求。其中一些是:

How do I Disable the swipe gesture of UIPageViewController?

Disable Page scrolling in UIPageViewController

Disable/enable scrolling in UIPageViewController

Restrict UIPageViewController (with TransitionStyleScroll) pan gesture to a certain area

以上所有指向完全禁用或限制平移手势到特定区域。

现在如果我采取完全禁用的方法:

如果我采取限制在某个区域的方法:


作者建议了一些技巧:

pvc.dataSource = nil // prevents paging

pvc.dataSource = `a valid dataSource object` // enables paging

所以,再次手动启用+禁用。跟踪方向变化和 enable/disable.

对于我的特定用例,这不安全,因为有可能多次分配数据源。


我认为还有其他方法无法修改以适应用例。

有没有捷径可以达到我的要求?

回答我自己的问题,因为我已经实现了我需要的。

子类化 UIPageViewController 是最简单的方法。我们必须找到页面视图控制器用来处理其平移手势相关工作的底层 UIScrollView。我们将向该内部滚动视图添加另一个 UIPanGestureRecognizer。此平移手势识别器本质上不会执行任何操作,但它会阻止内部平移手势识别器仅针对横向识别。

实施示例:

class CustomPageViewController: UIPageViewController, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        if let underlyingScrollView = view.subviews.compactMap({ [=10=] as? UIScrollView })
                                    .first {

            let pangestureRecognizer = UIPanGestureRecognizer()
            pangestureRecognizer.delegate = self
            underlyingScrollView.addGestureRecognizer(pangestureRecognizer)
            // at this point, the underlying scroll view will have two pan gesture
            // recognizer side by side. We have the control of our added pan gesture
            // recognizer through the delegate. We can conditionally recognize it or not
        }
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, 
         shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) 
         -> Bool {
        // Returning true from here means, page view controller will behave as it is
        // Returning false means, paging will be blocked
        // As I needed to block paging only for landscape orientation, I'm just returning
        // if orientation is in portrait or not
        return UIApplication.shared.statusBarOrientation.isPortrait
    }

}