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: Просто убедитесь, что делегат установлен для всех распознавателей.

  • Msgstr "wait_fences: не удалось получить ответ: 10004003"?
  • objective C: Как вы можете повернуть текст для UIButton и UILabel?
  • Как установить приложение Cocoa в качестве браузера по умолчанию?
  • Ошибка Apple Mach-O Linker при компиляции для устройства
  • Выполнение команды терминала из приложения Cocoa
  • iTunes Connect API
  • Ошибка UICollectionView Assertion
  • Анимированный gif не работает в наложении MKMapView с использованием MKOverlayRenderer
  • Как использовать UIPanGestureRecognizer для перемещения объекта? iPhone / IPad
  • Как -performSelector: withObject: afterDelay: работать?
  • Как анализировать длительность ISO-8601 в Objective C?
  • Interesting Posts

    Как сравнить даты в c #

    Недостаточно места на диске для обновления до Windows 10

    Случайно rsync –delete, / usr влияет, любой способ проверить и переустановить отсутствующий компонент?

    Слабая модель обработчика событий для использования с lambdas

    Статические поля в нулевой ссылке в Java

    Изменение размера изображения без потери качества

    Управление IE11 «Вы хотите открыть / сохранить» диалоговые windows в VBA

    Можно ли сделать каждый цикл в java в обратном порядке?

    Как переместить существующую установку Window 7 64bit в UEFI (из наследия)

    Проблема удаления GIT на окнах

    Различное поведение LIKE между моим приложением и мастером запросов Access

    Java: разделение запятой строки, но игнорирование запятых в кавычках

    YouTube не работает через прокси-сервер SSH-туннеля на IP-адрес в США

    Обновление Microsoft (MSU) не находит обновлений для других продуктов Microsoft (например, Office) после обновления MSU

    Перенаправление локальной локальной сети и интернет-трафика в VPN

    Давайте будем гением компьютера.