Tengo un problema y lo he descrito a continuación.
Estoy usando UIViewControllerContextTransitioning
para transiciones personalizadas.
Tengo 2 controladores de vista, el primer controlador de vista y el segundo controlador de vista.
Ahora quiero agregar un segundo controlador de vista en el primer controlador de vista con una animación. Lo logré, ahora el segundo controlador de vista es transparente, por lo que podemos ver el primer controlador de vista debajo del segundo controlador de vista.
Pero no puedo ver el controlador de la primera vista y solo puedo ver la pantalla negra debajo del controlador de la segunda vista.
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
if(self.isPresenting){
[self executePresentationAnimation:transitionContext];
}
else{
[self executeDismissalAnimation:transitionContext];
}
}
-(void)executePresentationAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
UIView* inView = [transitionContext containerView];
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
CGRect offScreenFrame = inView.frame;
offScreenFrame.origin.y = inView.frame.size.height;
toViewController.view.frame = offScreenFrame;
toViewController.view.backgroundColor = [UIColor clearColor];
fromViewController.view.backgroundColor = [UIColor clearColor];
inView.backgroundColor = [UIColor clearColor];
[inView insertSubview:toViewController.view aboveSubview:fromViewController.view];
// [inView addSubview:toViewController.view];
CFTimeInterval duration = self.presentationDuration;
CFTimeInterval halfDuration = duration/2;
CATransform3D t1 = [self firstTransform];
CATransform3D t2 = [self secondTransformWithView:fromViewController.view];
[UIView animateKeyframesWithDuration:halfDuration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
fromViewController.view.layer.transform = t1;
}];
[UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.5f animations:^{
fromViewController.view.layer.transform = t2;
}];
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:duration delay:(halfDuration - (0.3*halfDuration)) usingSpringWithDamping:0.7f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
toViewController.view.frame = inView.frame;
} completion:^(BOOL finished) {
[self.transitionContext completeTransition:YES];
}];
}
Cuando se [self.transitionContext completeTransition:YES];
llama, de repente desaparece el primer controlador de vista y aparece una pantalla negra debajo del segundo controlador de vista.
¿Alguien tiene idea? Gracias.
fuente
modalPresentationStyle = UIModalPresentationFullScreen
. Por supuesto, aún obtiene su animación de transición personalizada.Siento que el razonamiento detrás de esto debería explicarse mejor.
La vista desaparece porque saca la vista del controlador de la vista de presentación de su ubicación original (jerarquía de vista), la coloca dentro del containerView que proporciona su animador, pero nunca la devuelve después de que la animación ha terminado. Entonces, la vista del controlador de vista se elimina con su supervista (containerView) de la ventana por completo.
En iOS 7, el sistema siempre devolvía las vistas de los controladores de vista que están involucrados en la presentación (presentando y presentada) a sus lugares originales después de que la transición ha terminado de animarse automáticamente. Eso ya no sucede con algunos estilos de presentación en iOS 8.
La regla es muy simple: el animador solo debe manipular la vista del controlador de vista de presentación si la vista de ese controlador de vista se va a ocultar (eliminar de la jerarquía de vista) por completo al final de la transición . En otras palabras, significa que después de que finalice la animación de presentación inicial, solo la vista del controlador de vista presentada será visible y no la vista del controlador de vista de presentación. Por ejemplo, si configura la opacidad de la vista del controlador de vista presentado al 50% y usa UIModalPresentationFullScreen, no podrá ver la vista del controlador de vista de presentación debajo de la vista presentada, pero si usa UIModalPresentationOverFullscreen, lo hará (el
shouldRemovePresentersView
método de UIPresentationController es responsable de especificar eso).¿Por qué no permitir que el animador manipule la vista del controlador de vista de presentación en todo momento? En primer lugar, si la vista del controlador de la vista de presentación permanecerá visible después de que finalice la animación durante todo el ciclo de vida de la presentación, no es necesario animarla en absoluto, simplemente permanece donde está. En segundo lugar, si la propiedad de ese controlador de vista se transfiere al controlador de presentación, lo más probable es que el controlador de presentación no sepa cómo diseñar la vista de ese controlador de vista cuando sea necesario, por ejemplo, cuando cambia la orientación, pero el propietario original del controlador de vista de presentación sí. .
En iOS 8
viewForKey:
se introdujo el método para obtener vistas que manipula el animador. En primer lugar, es útil seguir la regla descrita anteriormente devolviendo nil siempre que el animador no deba tocar la vista. En segundo lugar, puede devolver una vista diferente para que el animador la anime. Imagine que está implementando una presentación similar a una hoja de formulario. En este caso, querrá agregar alguna sombra o decoración alrededor de la vista del controlador de vista presentado. El animador animará esa decoración en su lugar y la vista del controlador de vista presentada será un elemento secundario de la decoración.viewControllerForKey:
no desaparece, aún se puede usar si se necesita un acceso directo a los controladores de vista, pero el animador no debe hacer suposiciones sobre las vistas que necesita para animar.Hay varias cosas que puede hacer para solucionar correctamente un problema con la desaparición de la vista del controlador de la vista de presentación cuando la coloca explícitamente dentro de la vista del contenedor del animador:
Si no necesita animar la vista del controlador de la vista de presentación, use
viewForKey:
para obtener vistas para animar en lugar de llegar a ver las vistas del controlador directamente.viewForKey:
puede devolver puntos de vista nulos o incluso completamente diferentes.Si desea animar la vista de los controladores de vista de presentación se debe considerar el uso de
UIModalPresentationFullScreen
estilo o seguir utilizandoUIModalPresentationCustom
e implementar su propia subclase de UIPresentationController conshouldRemovePresentersView
regresarYES
. De hecho, la implementación de este método es la principal diferencia entre los controladores de presentación internos definidos porUIModalPresentationFullScreen
y losUIModalPresentationCustom
estilos, aparte del hecho de que este último le permite utilizar controladores de presentación personalizados.En todos los demás casos excepcionales, tendrá que devolver la vista del controlador de la vista de presentación a su ubicación original, como sugirieron otras respuestas.
fuente
viewControllerForKey:
'sview
solo cuandoviewForKey:
devuelve nil, y todavía tuve que volver a agregarlo a la ventana manualmente. ¿Tiene un ejemplo de código que funcione sin esta solución?viewForKey:
devuelve nil, entonces seguramente tendrá que volver a agregar la vista del controlador de vista de presentación a la ventana si la elimina en su animador. En caso de que viewForKey devuelva la vista del controlador de vista real, es seguro mover esa vista porque UIKit la volvería a mover a su posición original después de que finalice el ciclo de vida de la presentación.En iOS 8, debe manipular las vistas devueltas por en
viewForKey:
lugar de la.view
propiedad de los controladores de vista devueltos porviewControllerForKey:
. Esto no es particularmente claro en la documentación beta, pero si busca en la fuente de UIViewControllerTransitioning.h verá este comentario arribaviewControllerForKey:
:Entonces, en lugar de ajustar marcos, etc. de
toViewController.view
, use el valor de retorno de[transitionContext viewForKey:UITransitionContextToViewKey]
.Si su aplicación necesita ser compatible con iOS7 y / o Xcode 5, puede usar un método de categoría simple en UIViewController como el siguiente:
Luego, obtenga su
toViewController
yfromViewController
como de costumbre, pero obtenga las vistas usando[toViewController viewForTransitionContext:transitionContext]
.Editar: Parece haber un error, donde la vista del controlador de la vista de presentación es nula cuando se devuelve
viewForKey
, lo que le impide realizar transiciones modales que animen la vista de presentación (como deslizarse o voltearse horizontalmente). Presenté un error para iOS8 en rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). También vea el proyecto de muestra en http://github.com/bcherry/TransitionBugEdición 2: Gracias a graveley por la sugerencia, el uso de UIModalPresentationFullScreen soluciona el problema. Quizás esto no sea un error. Apple puede tener la intención de que UIModalPresentationCustom solo modifique la vista del modal entrante. Si desea modificar la vista saliente, ¿debe garantizar la presentación a pantalla completa de la nueva vista? En cualquier caso, debe utilizar
viewForKey
y UIModalPresentationFullScreen.fuente
manipulating
las opiniones de los VC o no ...viewForKey
error en el GM. ¿Otros también? ¿Ha encontrado una solución alternativa razonable?- viewForKey
// viewForKey: may return nil, lo que indicaría que el animador no debería manipular la vista del controlador de vista asociado. Regresarnil
no es un error.viewForKey
devuelve la vista desde y la vista. Entonces, tal vez sea intencional que devuelva nil para UIModalPresentationCustom. Estoy actualizando mi informe de errores y volveré a publicar aquí si tengo noticias de Apple al respecto.No configurar
modalPresentationStyle
UIModalPresentationCustom solucionó el problema para mí.En otras palabras, dejar el valor predeterminado de UIModalPresentationFullScreen en lugar de especificar UIModalPresentationCustom solucionó el problema de la vista que desaparecía. Tenga en cuenta que el protocolo UIViewControllerTransitioningDelegate todavía parece seguirse incluso cuando se deja esto en el valor predeterminado. Si mal no recuerdo, una vez UIModalPresentationCustom era un requisito.
Funciona hasta ahora, solo he probado esto para animaciones no interactivas.
fuente
viewForKey:
lugar de.view
en elviewControllerForKey:
soluciona todos los problemas para mí.Encontré esta respuesta extremadamente útil en un hilo relacionado de Lefteris: https://stackoverflow.com/a/27165723/3709173
Para resumirlo:
+1 en su transición personalizada, no agregue toView cuando esté sucediendo la animación de despido.
Demostrado aquí:
https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 ¡ sin ningún truco! es como magia! :)
fuente
En iOS 8, necesita crear un UIPresentationController e implementar el método siguiente, en UIViewControllerTransitioningDelegate.
Para obtener más información, vea el video de la WWDC 2014:
https://developer.apple.com/videos/wwdc/2014/?include=228
También hay un código de muestra de la WWDC llamado "LookInside: Presentation Controllers Adaptivity and Custom Animator Objects", que puede descargar de la página de códigos de muestra de la WWDC 2014.
Es posible que deba cambiar un poco el código de muestra. El método de inicio de UIPresentationController cambió a:
Antes se presentaba y luego se presentaba. Simplemente cámbielos y debería funcionar.
fuente
en lugar de [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; simplemente agregue: [inView addSubview: toViewController.view];
Puedes ver un ejemplo aquí: enlace y funciona en iOS 7 y iOS 8
fuente
Aquí hay una versión Objective C de la solución de Ash.
Tuve que cambiar el orden y llamar al método [transiciónContext completeTransition:] después de volver a agregar la vista para presentar un nuevo controlador de vista desde el bloque de finalización de despido de otro controlador de vista para que funcione correctamente.
No sé si esto lo solucionará para todos, pero funciona en mi aplicación. ¡Salud!
fuente
Encontré que esto funcionó bien para Obj-C:
Parece funcionar bien tanto en ios7 como en ios8.
fuente
Encontré que
viewForKey:UITransitionContextToViewKey
devuelve nulo en ios8. Entonces, si es nulo, tomo la vista desde el controlador de vista 'a'.Sin embargo, esto parece dar como resultado que la vista 'hasta' no se mueva del contenedor a la ventana cuando
completeTransition:YES
se llama. Entonces, siviewForKey:UITransitionContextToViewKey
devuelve nil, me caigo y hagotoVC.view
un seguimiento del hecho de que devolvió nil, y después de completarlo, lo muevo a la supervista inicial del contenedor (que resulta ser la ventana).Entonces, este código funciona tanto en iOS7 como en iOS8, y debería funcionar también en iOS9, incluso si lo corrigen o no.
fuente
Descubrí que este error (¡y muchos más!) Desaparece si configuras
modalPresentationStyle = UIModalPresentationFullScreen
. Por supuesto, aún obtiene su animación de transición personalizada.fuente
También me quedé atascado en este tema. Estaba buscando crear una transición personalizada con un fondo semitransparente en el que aún pudiera ver el controlador de vista del que venía, pero solo obtuve un fondo negro. Encontré que la respuesta de Mark Aron en este hilo me ayudó, pero está escrita en Objective C, así que aquí hay una versión Swift 3 de esa respuesta que he probado para iOS 9 e iOS 10:
Cree una subclase de UIPresentationController. Anule shouldRemovePresentersView a falso de la siguiente manera:
En el lugar en el que está creando una instancia del nuevo controlador de vista y configurando su delegado de transición, indique que desea que muestre un estilo de presentación modal personalizado de la siguiente manera:
Ahora anule el método presentationController de su UIViewControllerTransitioningDelegate y devuelva su UIPresentationController personalizado. Tenía el mío como una extensión de mi clase actual:
Otra cosa a tener en cuenta es que no debe intentar hacer referencia a su fromView en su clase presentAnimator. Esto será nulo y obtendrá un error en tiempo de ejecución. Aparte de eso, si implementa cosas como cosas, obtendrá su transición personalizada con su animación y un fondo semitransparente si hace uno.
fuente
presentationController(forPresented presented UIViewController,...
porque la API de Swift anterior no molestó al cumplidor, pero no recibió la llamada.Después de encontrarme con este problema, estaba muy confundido, porque había escrito algo casi idéntico no hace mucho que funcionó bien. Vine aquí en busca de respuestas para encontrar soluciones que parezcan bastante hacky, y no parecen entender la causa raíz ... en realidad es muy fácil de solucionar.
Algunas respuestas mencionan cambiar
modalPresentationStyle
a.overFullScreen
. Esto es correcto,.overCurrentContext
también funcionaría. Esto es lo que se espera y el comportamiento que documenta Apple. Pero, ¿por qué esto no funciona para todos? ¿Por qué todo el código hacky y las combinaciones de esto con algo más, y cosas locas que no deberías estar haciendo?Resulta que es necesario establecer el estilo de presentación ANTES DE CARGAR LA VISTA . No después de. Hágalo en init, o desde el controlador anterior, o como desee, siempre que sea antes de que se cargue la vista.
fuente
.overCurrentContext
antes de la carga de la vista (en elinit
controlador de vista) y el problema aún ocurreEl uso del nuevo UIModalPresentationOverCurrentContext lo arregló para mí. Mi transición original en iOS 7 era solo tener un fondo borroso de la vista debajo del modal.
fuente
Ok, chicos, creo que resuelvo un caso en el que 'un animador en funcionamiento' deja de funcionar correctamente cuando construyen una aplicación en iOS 13 y superior.
Env Xcode 11.1, iOS 13.1
Problema
Lo que quiero hacer es muy simple: tengo una vista de colección, cuando se toca una celda, pasará a una vista de detalle. En lugar de usar el aburrido estilo predeterminado de 'presentar modalmente', quiero hacerlo más interesante, así que escribí un animador para la transición del controlador de vista.
Configuré el segue en IB arrastrando y soltando desde mi colección VC al VC de detalle. El estilo de segue es 'Presentar modalmente' y la presentación se establece en 'Pantalla completa'.
Cuando muestra la vista detallada, todo funciona como se esperaba. Sin embargo, cuando descarto la vista de detalle y regreso a la vista de colección, solo puedo ver la vista de detalle animada, la vista de colección simplemente desaparece. He hurgado aquí y allá y tengo algunos descubrimientos.
1.Justo después de que se llame a la siguiente línea desde la función 'animateTransition ()', la vista de colección se reanuda y aparece
2. Mientras la vista de detalle no cubra completamente la vista de colección, la vista de colección no desaparecerá cuando regrese de la vista de detalle.
Solución
Para ser honesto, sé poco sobre cómo funciona la transición animada. Así que solo puedo seguir este post y el otro , prueba cada una de las respuestas. Desafortunadamente, ninguno de ellos funciona para mí. Finalmente, llegué a un punto en el que lo único que puedo modificar es el estilo de presentación de segue en IB (que debería haber hecho desde el principio). Cuando configuro la presentación en 'Pantalla completa', ocurre un milagro y mi problema se resuelve. La vista de detalles podría mostrarse en pantalla completa con animación y cuando se descartó, puedo ver tanto la vista de colección como la vista de fondo como la vista de detalle animada.
Luego, un descubrimiento más a lo largo del camino.
3.Para referirse a 'toView' y 'fromView', ambos métodos funcionan
De manera indirecta:
Directamente de manera:
Pero cuando cambié el estilo de segue a 'Pantalla completa', la forma directa devuelve 'nil' tanto para 'toView' como 'fromView' y solo funciona indirectamente, este problema también se menciona en otra publicación , así que creo que vale la pena para publicar mi pequeño descubrimiento aquí.
Espero que esto sea útil para alguien en el futuro.
fuente
Tenía el mismo problema al cerrar un controlador de vista de contenido.
Mi aplicación tiene este controlador de vista principal que muestra un controlador de vista secundario (presentando vc) modalmente. Luego, cuando se toca una subvista en childVC, muestra otra vc (que estoy llamando el controlador de vista de contenido (presentado vc))
Mi problema es que, al descartar el contentVC (ahora el vc de presentación), debería ir al VC secundario (ahora el VC presentado) pero tan pronto como finaliza mi transición personalizada, childVC desaparece repentinamente, mostrando el VC principal.
Lo que hice para resolver este problema fue
.modalPresentationStyle
del childVC presentado por parentVC del predeterminado.automatic
a.fullscreen
..modalPresentationStyle
de contentVC a.fullscreen
también.Esto resuelve el problema. pero no mostrará el VC de su hijo como una hoja de estilo de tarjeta en la parte superior de parentVC (cuando se usa
.overCurrentContext
o es automático) que es nuevo en iOS 13.Me encantaría saber si hay alguna solución que retenga la hoja de estilo de tarjeta para el childVC cuando la presenten los padres.
fuente
agrega un controlador de vista como hijo de otro controlador de vista.
verifique y avíseme.
fuente