UIPageViewController не возвращает никаких распознавателей жестов в iOS 6

Я пытаюсь отключить распознаватель жестов для UIPageViewController.

На iOS 5 я могу пропустить их и отключить.

for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) { if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) { recognizer.enabled = NO; } } 

На iOS 6 с использованием UIPageViewControllerTransitionStyleScroll нет распознавателей жестов, возвращаемых controllerом просмотра страниц.

осветление

Это можно свести к:

self.pageViewController.gestureRecognizers = 0, когда стиль перехода UIPageViewController настроен на прокрутку, поэтому я не могу получить доступ к распознавателям жестов.

Есть ли способ обойти это? Я не думаю, что я делаю что-то неправильно, так как переход на curl отлично работает.

Для такого поведения есть ошибка, обнаруженная в радаре . Итак, я уверен, что до тех пор, пока Apple не решит это, не будет возможности решить эту проблему.

Один из решений, который приходит мне на ум, заключается в создании прозрачного подзапроса поверх вашего UIPageViewController и добавления к нему UIPanGestureRecognizer для перехвата такого жеста, а не дальнейшего продвижения. Вы можете включить этот вид / распознаватель, когда требуется отключить жест.

Я попробовал его с комбинацией распознавателей жестов Pan и Tap, и он работает.

Это мой тестовый код:

 - (void)viewDidLoad { [super viewDidLoad]; UIPanGestureRecognizer* g1 = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(g1Pan:)] autorelease]; [self.view addGestureRecognizer:g1]; UITapGestureRecognizer* s1 = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(g1Tap:)] autorelease]; [self.view addGestureRecognizer:s1]; UIView* anotherView = [[[UIView alloc]initWithFrame:self.view.bounds] autorelease]; [self.view addSubview:anotherView]; UIPanGestureRecognizer* g2 = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(g2Pan:)] autorelease]; [anotherView addGestureRecognizer:g2]; } 

Когда g2 включен, это предотвратит распознавание g1 . С другой стороны, это не помешает s1 распознаваться.

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

Обнаружено это в UIPageViewController.h:

// Только заполненный, если стиль перехода – «UIPageViewControllerTransitionStylePageCurl». @property (nonatomic, readonly) NSArray * gestureRecognizers;

Итак, не ошибка – по дизайну pageViewController не получает распознавателей жестов, когда установлен стиль прокрутки.

Вы всегда можете попытаться отключить взаимодействие пользователя с подзаданием controllerа просмотра страницы:

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

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

Таким образом, установите источник данных на нуль, если вы хотите отключить прокрутку, а затем, когда вы хотите включить прокрутку, сбросьте источник данных.

т.е.

 // turns off paging pageViewController.datasource = nil // turns on paging pageViewController.datasource = self; 

Вы можете получить доступ к UIPanGestureRecognizer через UIScrollview из UIPageViewController.

 for (UIView *view in self.pageController.view.subviews) { if ([view isKindOfClass:[UIScrollView class]]) { UIScrollView *scrollView = (UIScrollView *)view; UIPanGestureRecognizer* panGestureRecognizer = scrollView.panGestureRecognizer; [panGestureRecognizer addTarget:self action:@selector(move:)]; } } 

Если UIPageViewControllers UIPanGestureRecognizer едет / глотает все события вдали от другого PanGestureRecognizer (например, скользящее меню).

Вы можете легко расширить решение для Берниса и заставить UIScrollViews PanGestureRecognizer потребовать, чтобы другой Recognizer завершился с ошибкой. Что-то вроде этого:

 for (UIView *view in pageViewController.view.subviews) { if ([view isKindOfClass:[UIScrollView class]]){ UIScrollView *scrollView = (UIScrollView *)view; [scrollView.panGestureRecognizer requireGestureRecognizerToFail:otherRecognizer]; } } 

Таким образом, прокрутка PanGestureRecognizer запускается только в тех областях, на которых я намеревался.

Это может оказаться не лучшим решением для будущего, поскольку мы требуем от Apple не изменять внутреннее использование UIPcViewViewControllers UIScrollView. но…

Предполагая, что вы можете найти распознаватели жестов и удалить их, очень хрупкий. Вы используете предполагаемые знания о том, как Apple использует инструменты UIPageViewController для обеспечения функциональности вашего приложения. Если это изменится (например, между iOS 5 и iOS 6), то приложение с кодом начнет вести себя непредсказуемыми способами. Это похоже на использование частного API – у вас нет гарантии, что он будет работать со следующей версией ОС.

Что произойдет, если вы используете методы KVC (Key Value Coding) для доступа к распознавателям? (Я не могу проверить это на данный момент.)

Быстрый тест может заключаться в том, чтобы получить количество жестов:

 [self.pageViewController countOfKey:@"gestureRecognizers"]; 

Если это сработает, вы можете продолжить поиск массива распознавателей:

 NSArray *recognizers = [self.pageViewController mutableArrayValueForKey:@"gestureRecognizers"]; 

Тонкий, но, может быть …

Редактировать: смог наконец проверить. Использовалось следующее:

 NSArray *pvcGRsNoKVC = [[NSArray alloc] initWithArray:self.pageViewController.gestureRecognizers]; NSArray *viewGRsNoKVC = [[NSArray alloc] initWithArray:self.view.gestureRecognizers]; NSArray *pvcGRsKVC = [[NSArray alloc] initWithArray:[self.pageViewController valueForKey:@"gestureRecognizers"]]; NSArray *viewGRsKVC = [[NSArray alloc] initWithArray:[self.view valueForKey:@"gestureRecognizers"]]; 

Это не имело никакого значения. Стиль завитки отлично работал в обоих направлениях; стиль прокрутки показал, что массивы не ноль, а пустой. Интересная вещь, однако, заключалась в том, что мнение ТАКЖЕ не отказалось от своих распознавателей – хотя функциональность прокрутки есть, поэтому у нее должен быть хотя бы распознаватель панорамы …

Другое решение, только для истории. Вы можете сделать любой вид, чтобы быть каким-то разрывом распознавателя жестов, и он должен работать в прямоугольнике этого вида. Должен быть другой UIPanGestureRecognizer с делегатом. Это может быть любой объект одним способом:

 static UIPageViewController* getPageViewControllerFromView(UIView* v) { UIResponder* r = v.nextResponder; while (r) { if ([r isKindOfClass:UIPageViewController.class]) return (UIPageViewController*)r; r = r.nextResponder; } return nil; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { if (getPageViewControllerFromView(otherGestureRecognizer.view)) { otherGestureRecognizer.enabled = NO; otherGestureRecognizer.enabled = YES; } return NO; } 

Вы можете использовать следующий class для разблокировки распознавателя:

 @interface GestureRecognizerBreaker : NSObject  { UIGestureRecognizer* breaker_; BOOL(^needsBreak_)(UIGestureRecognizer*); } - (id) initWithBreakerClass:(Class)recognizerClass checker:(BOOL(^)(UIGestureRecognizer* recognizer))needsBreak; - (void) lockForView:(UIView*)view; - (void) unlockForView:(UIView*)view; @end @implementation GestureRecognizerBreaker - (void) dummy:(id)r {} - (id) initWithBreakerClass:(Class)recognizerClass checker:(BOOL(^)(UIGestureRecognizer*))needsBreak { self = [super init]; if (!self) return nil; NSParameterAssert([recognizerClass isSubclassOfClass:UIGestureRecognizer.class] && needsBreak); needsBreak_ = needsBreak; breaker_ = [[recognizerClass alloc] initWithTarget:self action:@selector(dummy:)]; breaker_.delegate = self; return self; } - (BOOL) gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { if (needsBreak_(otherGestureRecognizer)) { otherGestureRecognizer.enabled = NO; otherGestureRecognizer.enabled = YES; } return NO; } - (void) lockForView:(UIView*)view { [view addGestureRecognizer:breaker_]; } - (void) unlockForView:(UIView*)view { [view removeGestureRecognizer:breaker_]; } @end 

Это работает, например, как одиночный:

 static GestureRecognizerBreaker* PageViewControllerLocker() { static GestureRecognizerBreaker* i = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ i = [[GestureRecognizerBreaker alloc] initWithBreakerClass:UIPanGestureRecognizer.class checker:^BOOL(UIGestureRecognizer* recognizer) { UIView* v = recognizer.view; UIResponder* r = v.nextResponder; while (r) { if ([r isKindOfClass:UIPageViewController.class]) return YES; r = r.nextResponder; } return NO; }]; }); return i; } 

После вызова -lockForView: жест controllerа страницы не работает при перетаскивании в рамку просмотра. Например, я хочу заблокировать все пространство моего controllerа представления. Поэтому в какой-то момент я вижу метод controllerа, который я вызываю

 [PageViewControllerLocker() lockForView:self.view]; 

И в другой момент

 [PageViewControllerLocker() unlockForView:self.view]; 

Внутри диспетчера просмотра страницы есть subview, называемый quieingscrollview, у него есть 3 распознавателя жестов, которые управляют controllerом просмотра страницы, чтобы заставить их использовать

 [[pageViewController.view.subviews objectAtIndex:0] gestureRecognizers] 

В моем случае у меня была панель «Информация» UIView, которая опустилась поверх моего UIPageViewController, но распознаватели жестов в режиме просмотра страниц препятствовали навигации через мою информационную панель.

Мое решение состояло в том, чтобы установить dataSource в nil, но также не позволять controllerу просмотра страниц обновлять фокус, пока информационная панель вверх:

 - (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context { if (self.infoPanel) { return NO; } else { return YES; } } 

Вы можете использовать методы делегата UIGestureRecognizer для улавливания и отключения любых жестов. Например, вы можете использовать этот обратный вызов делегата: gestureRecognizer:shouldReceiveTouch: Просто убедитесь, что делегат установлен для всех распознавателей.

  • objective @ Символ перед строк?
  • MKAnnotation, простой пример
  • Ошибка UIActivityViewController на iOS 8 iPads
  • Полноэкранный UIView со строкой состояния и наложением панели навигации наверху
  • Комплект iPhone Store «Не удается подключиться к iTunes Store»
  • Как написать данные в plist?
  • Звук не работает в iPhone Simulator?
  • Класс размера для iPad-портрета и ландшафтных режимов
  • Как скопировать объект в объекте c
  • Как использовать CaptiveNetwork для получения текущего имени точки доступа Wi-Fi
  • `` соглашение
  • Давайте будем гением компьютера.