如何仅针对横向禁用 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
以上所有指向完全禁用或限制平移手势到特定区域。
现在如果我采取完全禁用的方法:
- 我需要跟踪设备方向变化
- 当方向设置为横向时禁用
- 当方向更改为纵向时再次启用
如果我采取限制在某个区域的方法:
我需要找到某些区域
需要计算某个区域(在上一点中描述)
纵向和横向方向不同
纵向的某些区域需要是
整个UIPageViewController
范围
横向的某些区域需要是一个非常小的区域
(其框架可能是 0
、0
、1
、1
)用户将无法
进行平移操作。这个帧计算需要很
精确是因为我的 UIPageViewController
占据了整个范围
横向主屏幕。
然后可能需要再次跟踪不同的设备方向变化
某区域的计算
作者建议了一些技巧:
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
}
}
我有一个 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
以上所有指向完全禁用或限制平移手势到特定区域。
现在如果我采取完全禁用的方法:
- 我需要跟踪设备方向变化
- 当方向设置为横向时禁用
- 当方向更改为纵向时再次启用
如果我采取限制在某个区域的方法:
我需要找到某些区域
需要计算某个区域(在上一点中描述) 纵向和横向方向不同
纵向的某些区域需要是 整个
UIPageViewController
范围横向的某些区域需要是一个非常小的区域 (其框架可能是
0
、0
、1
、1
)用户将无法 进行平移操作。这个帧计算需要很 精确是因为我的UIPageViewController
占据了整个范围 横向主屏幕。然后可能需要再次跟踪不同的设备方向变化 某区域的计算
作者建议了一些技巧:
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
}
}