sirven que para los inicio gestos flotante boton assistive iphone objective-c uikit uipageviewcontroller

iphone - que - UIPageViewController no devuelve reconocedores de gestos en iOS 6



gestos iphone 8 (12)

¿Qué sucede si utiliza los métodos KVC (Key Value Coding) para acceder a los reconocedores? (No estoy donde puedo probar esto en este momento).

Una prueba rápida podría ser recuperar el número de gestureRecognizers:

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

Si eso funciona, puede ir más allá para recuperar la matriz de reconocedores:

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

Delgado, pero tal vez ...

Editar: pude finalmente probar. Usó lo siguiente:

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"]];

No hizo ninguna diferencia. El estilo rizo funcionaba bien en ambos sentidos; el estilo de desplazamiento mostraba las matrices como nulas, pero vacías. Sin embargo, una cosa interesante fue que la vista TAMBIÉN no renunció a sus reconocedores, aunque la funcionalidad de desplazamiento está ahí, por lo que debe tener al menos un reconocedor de panorama ...

Estoy tratando de desactivar el reconocedor de gestos pan para un UIPageViewController.

En iOS 5 puedo recorrerlos y desactivarlos.

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

En iOS 6 con UIPageViewControllerTransitionStyleScroll no hay reconocedores de gestos devueltos por el controlador de vista de página.

Aclaración

Esto puede reducirse a:

self.pageViewController.gestureRecognizers = 0 cuando el estilo de transición de UIPageViewController está configurado para desplazarse, por lo que no puedo acceder a los reconocedores de gestos.

¿Hay alguna forma de evitar esto? No creo que esté haciendo nada mal ya que la transición de curvatura funciona bien.


Asumir que puedes encontrar los reconocedores de gestos y eliminarlos es muy frágil. Está utilizando el conocimiento supuesto de cómo Apple utiliza implementos UIPageViewController para proporcionar funcionalidad en su aplicación. Si esto cambia (como entre iOS 5 e iOS 6), entonces la aplicación de código comenzará a comportarse de forma inesperada. Es casi como usar una API privada; no tienes garantía de que funcione con la próxima versión del sistema operativo.


De acuerdo con el archivo de encabezado UIPageViewController, cuando el origen de datos es nulo, la navegación basada en gestos está deshabilitada.

Por lo tanto, establezca el origen de datos en cero cuando desee deshabilitar el deslizamiento, luego, cuando desee habilitar deslizar, reinicie el origen de datos.

es decir

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


Dentro del pageviewcontroller hay una subvista llamada quieingscrollview que tiene 3 reconocedores de gestos que controlan el controlador de vista de página para que los use

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


En mi caso, tenía un "Panel de información" de UIView que bajaba sobre mi UIPageViewController, pero los reconocedores de gestos del controlador de vista de página interferían con la navegación a través de mi panel de información.

Mi solución fue establecer dataSource en cero, pero también no permitir que el controlador de vista de página actualice el foco mientras el panel de información está activo:

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


Encontré esto en UIPageViewController.h:

// Solo se llena si el estilo de transición es ''UIPageViewControllerTransitionStylePageCurl''. @property (nonatomic, readonly) NSArray * gestureRecognizers;

Por lo tanto, no es un error: por diseño, pageViewController no obtiene reconocimientos de gestos cuando se establece el estilo de desplazamiento.


Hay un error presentado en el radar por este comportamiento. Entonces, apuesto a que hasta que Apple lo solucione no habrá ninguna posibilidad de resolver esto.

Una solución que se me viene a la mente es colocar una subvista transparente encima de su UIPageViewController y agregarle un UIPanGestureRecognizer para interceptar ese tipo de gesto y no avanzar más. Puede habilitar esta vista / reconocedor cuando se requiera deshabilitar el gesto.

Lo intenté con una combinación de reconocedores de gestos Pan y Tap y funciona.

Este es mi código de prueba:

- (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]; }

Cuando g2 está habilitado, evitará que g1 sea ​​reconocido. Por otro lado, no impedirá que s1 sea reconocido.

Entiendo que esto es un hack, pero ante un error aparente en UIPageViewController (al menos, el comportamiento real es descaradamente diferente de lo que dice la referencia), no veo ninguna solución mejor.


Otra solución, solo para la historia. Puede hacer que cualquier vista sea un interruptor de reconocimiento de gestos y debería funcionar en el rectángulo de esa vista. Debe haber otro UIPanGestureRecognizer con delegado. Puede ser cualquier objeto con un método:

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; }

Puede utilizar la siguiente clase para fines de detección de interruptores:

@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

Esto es obras, por ejemplo, como singletone:

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; }

Después de llamar a -lockForView: el gesto del controlador de página no funciona al arrastrar en el marco de la vista. Por ejemplo, quiero bloquear todo el espacio de mi controlador de vista. Entonces, en algún punto en vista del método de control que yo invoco

[PageViewControllerLocker() lockForView:self.view];

Y en otro punto

[PageViewControllerLocker() unlockForView:self.view];


Puede acceder al UIPanGestureRecognizer a través de UIScrollview desde 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:)]; } }


Puede utilizar los métodos de delegado de UIGestureRecognizer para capturar y deshabilitar cualquier gesto. Por ejemplo, podría usar esta devolución de llamada de delegado: gestureRecognizer:shouldReceiveTouch: Solo asegúrese de configurar el delegado para todos los reconocedores.


Si el UIPageViewControllers UIPanGestureRecognizer está comiendo / tragando todos los eventos lejos de otro PanGestureRecognizer (por ejemplo, un menú deslizante).

Puede ampliar fácilmente la solución Bernies y hacer que UIScrollViews PanGestureRecognizer requiera que el otro Recognizer falle. Algo como esto:

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

De esta forma, el desplazamiento de PanGestureRecognizer solo se activa en las áreas que yo pretendía.

Puede que esta no sea la mejor solución para probar el futuro, ya que le pedimos a Apple que no cambie el uso interno de UIScrollView de UIPageViewControllers. pero...


Siempre puede intentar deshabilitar la interacción del usuario en la vista secundaria del controlador de vista de página:

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