Подтвердить что ты не робот

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

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

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

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

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

Разъяснение

Это можно свернуть до:

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

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

4b9b3361

Ответ 1

Для такого поведения есть ошибка зарегистрированная в радаре. Итак, я уверен, что до тех пор, пока 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 (по крайней мере, фактическое поведение явно отличается от состояния ссылки), я не вижу лучшего решения.

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

Итак, установите источник данных на нуль, если вы хотите отключить прокрутку, тогда, когда вы хотите включить прокрутку, reset источник данных.

то есть.

// turns off paging
pageViewController.datasource = nil

// turns on paging
pageViewController.datasource = self;

Ответ 5

Вы можете получить доступ к 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:)];
    }
}

Ответ 6

Если 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. но...

Ответ 7

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

Ответ 8

Что произойдет, если вы используете методы 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"]];

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

Ответ 9

Другое решение, только для истории. Вы можете сделать любой вид каким-то разрывом распознавания жестов, и он должен работать в этом прямоугольнике вида. Должен быть другой 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;
}

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

@interface GestureRecognizerBreaker : NSObject <UIGestureRecognizerDelegate>
{
    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: жест управления страничным страницей не работает при перетаскивании в рамку просмотра. Например, я хочу заблокировать все пространство моего контроллера представления. Поэтому в какой-то момент я вижу метод контроллера

[PageViewControllerLocker() lockForView:self.view];

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

[PageViewControllerLocker() unlockForView:self.view];

Ответ 10

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

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

Ответ 11

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

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

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

Ответ 12

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