Как отключить жестов салфетки 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")
}
}