ios6 uipageviewcontroller

ios6 - UIPageViewController navega a la página incorrecta con el estilo de transición de desplazamiento



(5)

Este error todavía existe en iOS9. Estoy usando la misma solución que George Tsifrikas publicó anteriormente, pero una versión Swift:

pageViewController.setViewControllers([page], direction: direction, animated: true) { done in if done { dispatch_async(dispatch_get_main_queue()) { self.pageViewController.setViewControllers([page], direction: direction, animated: false, completion: {done in }) } } }

Mi UIPageViewController funcionaba bien en iOS 5. Pero cuando apareció iOS 6, quería usar el nuevo estilo de transición de desplazamiento (UIPageViewControllerTransitionStyleScroll) en lugar del estilo de enrollamiento de página. Esto causó que mi UIPageViewController se rompiera.

Funciona bien, excepto justo después de llamar a setViewControllers:direction:animated:completion: Después de eso, la próxima vez que el usuario se desplace manualmente una página, obtendremos la página incorrecta. ¿Qué está mal aquí?


Esto es realmente un error en UIPageViewController. Ocurre solo con el estilo de desplazamiento (UIPageViewControllerTransitionStyleScroll) y solo después de llamar a setViewControllers:direction:animated:completion: with animated: YES . Por lo tanto, hay dos soluciones:

  1. No utilice UIPageViewControllerTransitionStyleScroll.

  2. O, si llama a setViewControllers:direction:animated:completion: use solo animated:NO .

Para ver el error claramente, llame a setViewControllers:direction:animated:completion: y luego, en la interfaz (como usuario), navegue a la izquierda (atrás) a la página anterior manualmente. Volverá a la página incorrecta: no fue la página anterior, sino la página en la que se encontraba cuando setViewControllers:direction:animated:completion: se llamó.

El motivo del error parece ser que, al usar el estilo de desplazamiento, UIPageViewController realiza algún tipo de almacenamiento interno en caché. Por lo tanto, después de la llamada a setViewControllers:direction:animated:completion: no se puede borrar su caché interno. Cree que sabe lo que es la página anterior. Por lo tanto, cuando el usuario navega hacia la izquierda a la página anterior, UIPageViewController no puede llamar al método pageViewController:viewControllerBeforeViewController: o lo llama con el controlador de vista actual incorrecto.

He publicado una película que demuestra claramente cómo ver el error:

http://www.apeth.com/PageViewControllerBug.mov

EDITAR Este error probablemente se solucionará en iOS 8.

EDITAR Para otra solución interesante para este error, vea esta respuesta: https://.com/a/21624169/341994


Mi solución para este error fue crear un bloque cuando terminé que estaba configurando el mismo controlador de vista pero sin animación

__weak YourSelfClass *blocksafeSelf = self; [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){ if(finished) { dispatch_async(dispatch_get_main_queue(), ^{ [blocksafeSelf.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];// bug fix for uipageview controller }); } }];


Here hay una esencia "áspera" que junté. Contiene una alternativa UIPageViewController que sufre de Alzheimer (es decir, no tiene el almacenamiento en caché interno de la implementación de Apple).

Esta clase no está completa, pero funciona en mi situación (a saber: desplazamiento horizontal).


DECLARACIÓN:

Parece que Apple ha notado que los desarrolladores están utilizando UIPageViewController en aplicaciones muy diferentes que van más allá de las intenciones originales en las que Apple basó sus opciones de diseño en primer lugar. En lugar de usarlo de forma lineal por gestos, el PVC se usa a menudo para saltar programáticamente a posiciones aleatorias dentro de un entorno estructurado. Así que han mejorado su implementación de UIPageViewController y la clase ahora está llamando a ambas devoluciones de llamada de DataSource

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController

después de configurar un nuevo contentViewController en UIPageViewController con

[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];

incluso si un giro animado de páginas sugiere un progreso lineal en, por ejemplo, una jerarquía de páginas como un libro o PDF con páginas consecutivas. Aunque, dudo que a Apple desde un punto de vista HIG le guste ver que el PVC se use de esta manera, pero no rompe la compatibilidad, fue una solución fácil, así que eventualmente lo hicieron. En realidad, es solo una llamada más de uno de los dos métodos de DataSource que es absolutamente innecesario en un entorno lineal donde las páginas (ViewControllers) ya se han cobrado para su uso posterior.

Sin embargo, incluso si esta mejora puede ser muy útil para ciertos casos de uso, el comportamiento inicial de la clase NO debe considerarse un error. El hecho de que muchos desarrolladores lo hagan, también en otras publicaciones en SO que acusan a UIPageViewController de mala conducta, hace hincapié en una idea errónea ampliamente difundida de su diseño, propósito y funcionalidad.

Sin intentar ofender a ninguno de mis colegas desarrolladores aquí en esta gran instalación, no obstante, decidí no eliminar mi "disquisición" inicial que explica claramente a la OP la mecánica del PVC y por qué cree que tiene que lidiar con un error aquí. .

¡Esto también podría ser de utilidad para cualquier otro desarrollador que también tenga dificultades con algunas complejidades en la implementación de UIPageViewController!

RESPUESTA ORIGINAL:

Después de haber leído todas las respuestas una y otra vez, incluida la aceptada, solo queda una cosa más que decir ...

El diseño de UIPageViewController es absolutamente impecable y todos los trucos que envías para evitar un supuesto error no son más que remedios para tus propias suposiciones erróneas porque, en primer lugar, ¡hiciste el tonto!

¡NO HAY UN ERROR EN TODO! Sólo estás luchando contra el marco. ¡Te explicaré por qué!

¡Se habla tanto de números de página e índices! ¡Estos son conceptos que el controlador no conoce NADA ! Lo único que sabe es que está mostrando algo de contenido (por cierto, proporcionado por usted como dataViewController ) y que puede hacer algo como una animación de derecha / izquierda para imitar un giro de página. CURL o SCROLL ... !!!

En el mundo de pageViewController solo existe un SPACE actual (llamémoslo así para evitar confusiones con las páginas y los índices).

Cuando inicialmente configura un controlador de página , solo le importa este SPACE . Solo cuando comienza a panoramizar su vista, comienza a preguntarle a su DataSource qué debe mostrar eventualmente en caso de que ocurra un giro hacia la izquierda / derecha. Cuando comienza a desplazarse hacia la izquierda, el PVC solicita primero el BEFORE-SPACE y luego el AFTER-SPACE , en caso de que comience a la derecha, lo hará al revés.

Después de la animación completa (se visualiza un nuevo SPACE en la vista del PVC), el PVC considera este SPACE como su nuevo centro del universo y, mientras lo hace, le pregunta a DataSource sobre el que aún no sabe nada. En caso de un giro completo a la derecha, quiere saber sobre el nuevo espacio AFTER y en caso de un giro completo a la izquierda, solicita un nuevo espacio BEFORE .

El espacio BEFORE (desde antes de la animación) está en caso de un giro a la derecha completamente obsoleto y se desasigna lo antes posible. El center antiguo es ahora el nuevo BEFORE y el anterior AFTER es el nuevo center . Todo cambió un paso a la derecha.

Entonces, no se habla de '' qué página '' o '' cualquier índice '' - simplemente hay un espacio BEFORE o AFTER . Si devuelve NIL a una de las devoluciones de llamada de DataSource el PVC simplemente asume que está en un extremo de su range of SPACES . Si devuelve NIL a ambas devoluciones de llamada, se supone que está mostrando el one and only SPACE hay y nunca más volverá a llamar una devolución de llamada de DataSource . La lógica depende de ti! ¡Usted define páginas e índices en su código! No el PVC !!!

Para el usuario de la clase hay dos formas de interactuar con el PVC.

  • A pan-gesture that indicates whether a turn to the BEFORE/AFTER space is desired
  • A method - namely setViewControllers:direction:animated:completion:

Este método hace exactamente lo mismo que el gesto de panorámica. Está indicando la dirección (por ejemplo, UIPageViewControllerNavigationDirectionBackward/Forward ) para la animación, si hay una intención, que en otras palabras simplemente significa -> ir a BEFORE o AFTER ...

Nuevamente, sin mencionar índices, números de página, etc ... !!!

¡Es solo una forma programática de lograr lo mismo que un gesto! Y el PVC está haciendo lo correcto al mostrar nuevamente el contenido antiguo al volver a la izquierda después de haberse movido a la derecha en primer lugar. Recuerde: ¡es solo mostrar contenido (que usted proporciona) de manera estructurada, que es un ''single page turn'' una ''single page turn'' por diseño!

Ese es el concepto de un giro de página - o BOOK, ¡si te gusta más ese término!

El hecho de que usted lo complique al enviar la PÁGINA 8 después de la PÁGINA 1 no significa que el PVC se preocupe por su retorcida opinión de cómo debería funcionar un libro. Y el usuario de tus aplicaciones tampoco. Girar a la derecha y volver a la izquierda definitivamente debería resultar en llegar a la página original, SI se hace con una animación. Y depende de USTED corregir el error al encontrar una solución para el desastre. No culpes al UIPageViewController . ¡Está haciendo su trabajo perfectamente!

Solo pregúntese: ¿haría lo mismo con una animación PAGE-CURL ? NO ? Bueno, tampoco deberías con una animación SCROLL !!! ¡Un giro de página animado es un giro de página y solo un giro de página! En cualquier modo! ¡Y si decides arrancar la PÁGINA 2 a la PÁGINA 7 de tu LIBRO, está perfectamente bien! Pero no espere que UIPageViewController invente una PÁGINA 7 inexistente cuando regrese a la página reciente a menos que USTED le diga que las cosas han cambiado ...

Si realmente quieres lograr un salto descoordinado a otro lugar, ¡hazlo sin una animación! En la mayoría de los casos, esto no será muy elegante, pero es posible ...

¡Y el PVC incluso juega muy bien a lo largo! Cuando salte a un nuevo SPACE sin animación, le pedirá que continúe por el camino para el controlador BEFORE y AFTER . Así que su lógica de aplicación puede mantenerse al día con el PVC ...

Pero con una animación que siempre está transmitiendo, muévase al espacio anterior / siguiente ( BEFORE - AFTER ). Así que, lógicamente, no hay ninguna necesidad de que el PVC vuelva a preguntar sobre un espacio que ya conoce cuando se anima la página.

Si quieres ver la PÁGINA 7 cuando vuelves a la izquierda después de haber animado desde la PÁGINA 1 a la derecha, bueno, diría que ese es definitivamente tu propio problema.

Y en caso de que esté buscando una solución mejor que el truco de ''compleción completa'' de la respuesta aceptada (porque con eso está haciendo un trabajo de antemano para algo que posiblemente ni siquiera se use más adelante) use el reconocedor de gestos delegar:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

Configure el DataViewController de su PVC aquí (sin animación) si realmente desea volver a la izquierda a la PÁGINA 7 y se le pedirá al DataSource BEFORE y AFTER y puede enviar la página que desee! Con una bandera o un ivar que debería haber escondido al realizar su salto incontrolado de la PÁGINA 1 a la 8, esto no debería ser un problema ...

Y cuando la gente sigue quejándose de un error en el PVC (hacer 2 vueltas de página cuando se supone que debe hacerlo solo 1 vuelta), señale este artículo.

El mismo problema: activar un método setViewControllers no animado dentro del gesto de transición causará exactamente el mismo caos. Piensas que configuraste el nuevo centro - se le pide al DataSource el nuevo BEFORE - AFTER dataController - restableces tu cuenta de índice ... - Bueno, eso parece estar bien ...

Pero, después de todo ese negocio, el PVC finaliza su transición / animación y desea saber sobre el siguiente dataViewController ( BEFORE o AFTER ) y también activa el DataSource . Eso es totalmente justificado! Necesita saber dónde se encuentra en su pequeño BEFORE - CENTER - AFTER mundo y estar preparado para el próximo turno.

Pero su lógica de programa agrega otra cuenta de índice ++ a su lógica y, de repente, ¡¡tiene 2 giros de página !! Y ese es uno fuera de donde crees que estás.

¡Y USTED tiene que dar cuenta de eso! No UIPageViewController !

¡Ese es exactamente el punto del DataSourceProtocol que solo tiene dos métodos! ¡Quiere ser lo más genérico posible, dejándote el espacio y la libertad para definir tu propia lógica y no quedarte atrapado con las ideas especiales y los casos de uso de otra persona! La lógica depende completamente de ti. Y solo porque encuentras funciones como

- (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard position:(GSPositionOfDataViewController)position; - (NSUInteger)indexOfViewController:(DataViewController *)viewController;

¡en todas las aplicaciones de muestra copiadas / pegadas en la nube no significa necesariamente que tenga que comer esa comida precocinada! ¡Extiéndelos como quieras! Solo mire arriba - en mi firma encontrará un argumento de ''position:'' ! Extendí esto para saber más adelante si un giro de página completado era un giro a la derecha o a la izquierda. ¡Porque el delegado lamentablemente solo te dice si tu turno se completó o no! ¡No te dice sobre la dirección! Pero esto a veces importa para el conteo de índices, dependiendo de la necesidad de su aplicación ...

Vuélvete loco, son tuyos.

¡CÓDIGO FELIZ !!!