在我的情况下,父UIViewController
包含UIPageViewController
,其中包含UINavigationController
,其中包含UIViewController
。我需要向最后一个视图控制器添加滑动手势,但滑动处理就像它们属于页面视图控制器一样。我尝试以编程方式和通过xib执行此操作,但没有结果。
据我所知,在UIPageViewController
处理手势之前我无法实现目标。如何解决这个问题?
答案 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回答类似
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)
有一种比大多数答案建议的方法简单得多的方法,即在nil
和viewControllerBefore
数据源回调中返回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
}
}
}