Как отключить жестов салфетки UIPageViewController?

В моем случае родительский UIViewController содержит UIPageViewController который содержит UINavigationController который содержит UIViewController. Мне нужно добавить жест смахивания к последнему контроллеру представления, но смахивания обрабатываются так, как если бы они принадлежали контроллеру просмотра страницы. Я пытался сделать это как программно, так и через XIB, но безрезультатно.

Поэтому, насколько я понимаю, я не смогу достичь своей цели, пока UIPageViewController не UIPageViewController его жесты. Как решить эту проблему?

Ответ 1

Задокументированный способ предотвращения прокрутки UIPageViewController заключается в том, чтобы не присваивать свойство dataSource. Если вы назначите источник данных, он перейдет в режим навигации, основанный на жестов, который вы пытаетесь предотвратить.

Без источника данных вы вручную предоставляете контроллеры представлений, когда хотите использовать метод setViewControllers:direction:animated:completion, и он будет перемещаться между контроллерами представления по требованию.

Вышеизложенное можно сделать из документации Apple UIPageViewController (обзор, второй абзац):

Чтобы поддерживать навигацию на основе жестов, вы должны предоставить свои контроллеры представлений, используя объект источника данных.

Ответ 2

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

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

        view.scrollEnabled = NO;
    }
}

Ответ 3

Я перевежу ответ user2159978 на Swift

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

Ответ 4

Реализация решения @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

Ответ 5

Изменить: этот ответ работает только для стиля завитки страницы. Jessc answer намного лучше: работает независимо от стиля и опирается на документированное поведение.

UIPageViewController раскрывает свой массив распознавателей жестов, которые вы можете использовать для их отключения:

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

Ответ 6

Я боролся с этим какое-то время и думал, что должен опубликовать свое решение, следуя из ответа Jessc; удаление источника данных PageViewController.

Я добавил это в свой класс PgeViewController (связанный с моим контроллером просмотра страниц в раскадровке, наследует как UIPageViewController, так и UIPageViewControllerDataSource):

static func enable(enable: Bool){
    let appDelegate  = UIApplication.sharedApplication().delegate as! AppDelegate
    let pageViewController = appDelegate.window!.rootViewController as! PgeViewController
    if (enable){
        pageViewController.dataSource = pageViewController
    }else{
        pageViewController.dataSource = nil
    }
}

Это может быть вызвано, когда появляется каждый под просмотр (в этом случае его отключить);

override func viewDidAppear(animated: Bool) {
    PgeViewController.enable(false)
}

Я надеюсь, что это поможет кому-то, но не так чисто, как хотелось бы, но не слишком хладнокровно и т.д.

EDIT: если кто-то хочет перевести это в Objective-C, пожалуйста:)

Ответ 7

Если вы хотите, чтобы ваш UIPageViewController поддерживал возможность прокрутки, позволяя вашим элементам управления контентом использовать свои функции (проведите по удалению и т.д.), просто отключите canCancelContentTouches в UIPageViewController.

Поместите это в свою функциональность UIPageViewController viewDidLoad. (Swift)

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

UIPageViewController имеет автогенерируемое подзапрос, которое обрабатывает жесты. Мы можем помешать этим подзонам отменить жесты содержимого.

С...

Проведите по экрану в таблицеView, который находится внутри pageViewController

Ответ 8

Полезное расширение 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
            }
        }
    }
}

Ответ 9

Я решил это так (Swift 4.1)

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

Ответ 10

Похоже на @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
        }
    }

Ответ 11

Быстрый способ ответа @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
    }
}

Ответ 12

Перевод @user2159978 ответа на С#:

foreach (var view in pageViewController.View.Subviews){
   var subView = view as UIScrollView;
   if (subView != null){
     subView.ScrollEnabled = enabled;
   }
}

Ответ 13

Спасибо @user2159978 ответ.

Я делаю это немного более понятным.

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

Ответ 14

(Swift 4) Вы можете удалить жест-распознаватель вашей страницы ViewController:

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

Если вы предпочитаете в расширении:

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

и pageViewController.removeGestureRecognizers

Ответ 15

Объявите это так:

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

Тогда используйте это так:

scrollView?.isScrollEnabled = true //false

Ответ 16

уже заданный ответ pageViewController.view.isUserInteractionEnabled = false

Ответ 17

Ответы, которые я нашел, выглядят очень запутанными или неполными для меня, поэтому вот полное и настраиваемое решение:

Шаг 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")
    }
}