"From View Controller" desaparece con UIViewControllerContextTransitioning

105

Tengo un problema y lo he descrito a continuación.

Estoy usando UIViewControllerContextTransitioningpara 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.

NiravPatel
fuente

Respuestas:

98

Estaba teniendo el mismo problema aquí, parece un error en iOS 8. He archivado un radar .

Solía Reveal para inspeccionar la jerarquía de la vista después de que la pantalla se queda en negro. La clave UIWindowestá completamente vacía, ¡sin jerarquía de vistas!

Revelado

Jugué un poco y parece que hay una solución fácil, para casos simples. Puede volver a agregar la toViewControllervista como una subvista de la ventana clave:

transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow!.addSubview(toViewController.view)

Lo he comprobado y la ventana clave rootViewControllertodavía está configurada correctamente, así que está bien. No estoy seguro de qué pasaría si presentara su controlador desde un controlador modal ya presentado, por lo que para casos más complejos, tendrá que experimentar.

Surco de ceniza
fuente
2
También he visto este problema. iOS 8 introduce un nuevo método y claves para acceder a fromView y toView (Nota: controlador no de vista) Parece que estas referencias no se pierden durante la transición. Puede agregarlos a la vista del contenedor como lo haría normalmente si los hubiera recuperado de los controladores de vista.
tapi
1
Estaba viendo una rareza similar de iOS 8 al intentar agregar subvistas a la vista de mi controlador de navegación, en viewDidLoad. Volver a agregar la vista de navigationController a keyWindow pareció funcionar, ¡muchas gracias, Ash!
taber
1
Todavía veo esto en GM (y esta solución todavía funciona). ¿Los demás ven lo mismo? ¿Es esto solo un cambio en la API?
rjkaplan
21
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.
Chris
1
Gracias @AshFurrow. ¡Buena solución hasta que se solucione!
Kandelvijaya
78

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 shouldRemovePresentersViewmé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:

  1. 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.

  2. Si desea animar la vista de los controladores de vista de presentación se debe considerar el uso de UIModalPresentationFullScreenestilo o seguir utilizando UIModalPresentationCustome implementar su propia subclase de UIPresentationController con shouldRemovePresentersViewregresar YES. De hecho, la implementación de este método es la principal diferencia entre los controladores de presentación internos definidos por UIModalPresentationFullScreeny los UIModalPresentationCustomestilos, aparte del hecho de que este último le permite utilizar controladores de presentación personalizados.

  3. 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.

egdmitry
fuente
2
Eso es muy extraño porque este código se basa en viewControllerForKey:'s viewsolo cuando viewForKey: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?
Ash Surrow
Bueno, si 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.
egdmitry
Gracias por explicar el razonamiento detrás de este problema. Estás absolutamente en lo correcto. Mover la posición de la vista en la jerarquía de vistas sin reemplazarla obviamente la haría desaparecer (¡publique iOS 8, y estoy trabajando con iOS 10 ahora mismo!) Gracias por aclarar.
Clay Ellis
1
Gracias egdmitry por tu aclaración. Lo que plantea otra pregunta que es: ¿cómo crees que debería implementar una presentación similar a la de revelar ? ¿Uno de esos muy comunes hoy en día donde la vista de presentación se desliza parcialmente para mostrar la vista presentada debajo? En este escenario, tanto la vista de presentación como la vista presentada deben estar en pantalla y la vista de presentación es la animada.
Andrea
70

En iOS 8, debe manipular las vistas devueltas por en viewForKey:lugar de la .viewpropiedad de los controladores de vista devueltos por viewControllerForKey:. Esto no es particularmente claro en la documentación beta, pero si busca en la fuente de UIViewControllerTransitioning.h verá este comentario arriba viewControllerForKey::

// Currently only two keys are defined by the
// system - UITransitionContextToViewControllerKey, and
// UITransitionContextFromViewControllerKey.
// Animators should not directly manipulate a view controller's views and should
// use viewForKey: to get views instead.
- (UIViewController *)viewControllerForKey:(NSString *)key;

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:

- (UIView *)viewForTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        NSString *key = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey] == self ? UITransitionContextFromViewKey : UITransitionContextToViewKey;
        return [transitionContext viewForKey:key];
    } else {
        return self.view;
    }
#else
    return self.view;
#endif
}

Luego, obtenga su toViewControllery fromViewControllercomo 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/TransitionBug

Edició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 viewForKeyy UIModalPresentationFullScreen.

bcherry
fuente
2
¡El error de viewForKey me estaba volviendo loco! - Gracias por archivar. FWIW, mi transición está funcionando bien al obtener la vista de UITransitionContextToViewControllerKey, pero mi transición solo aplica una transformación a toda la vista. No estoy seguro de si eso debería interpretarse como manipulatinglas opiniones de los VC o no ...
MathewS
1
Vaya, eso es una locura. No vi eso en las diferencias, probablemente porque es solo un pequeño comentario. Realmente frustrante cuando Apple hace un truco como este. Cruzaron los dedos sobre su radar.
Ash Surrow
También veo el viewForKeyerror en el GM. ¿Otros también? ¿Ha encontrado una solución alternativa razonable?
rjkaplan
2
Pensé de acuerdo con el comentario de - viewForKey// viewForKey: may return nil, lo que indicaría que el animador no debería manipular la vista del controlador de vista asociado. Regresar nilno es un error.
Ken Kuan
4
@kenKuan, puede que tengas razón. cuando se usa UIModalPresentationFullScreen, viewForKeydevuelve 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.
bcherry
24

No configurar modalPresentationStyleUIModalPresentationCustom 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.

graveley
fuente
1
Guau. ¡Eso fue todo! Probé sin modalPresentationStyle en iOS7 y 8 y funciona find en ambos. ¡¡Gracias!!
Ah Ryun Moon
1
¡Gracias! Esto combinado con el uso en viewForKey:lugar de .viewen el viewControllerForKey:soluciona todos los problemas para mí.
bcherry
1
Esto me solucionó el problema sin usar viewForKey, pero supongo que también debería usarse.
Kevin Sliech
5
Aunque esto parece solucionar el problema, es importante tener en cuenta que la pantalla detrás de su controlador de vista se volverá negra una vez que se muestre. Esto es importante si su controlador de vista no es de pantalla completa.
The dude
16

Encontré esta respuesta extremadamente útil en un hilo relacionado de Lefteris: https://stackoverflow.com/a/27165723/3709173

Para resumirlo:

  1. establece modalPresentationStyle en .Custom
  2. subclase UIPresentationController, anular shouldRemovePresentersView (con NO)
  3. anule presentationControllerForPresentedViewController en su clase TransitionDelegate y devuelva su UIPresentationController personalizado

+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! :)

Mark Aron Szulyovszky
fuente
1
Esta es la verdadera respuesta correcta. Sin trucos de magia como en el aceptado. ¡Gracias, Mark!
Andrei Malygin
Desafortunadamente, esto no funciona en iOS 12.4, Xcode 10.3. La pantalla se vuelve negra después de que se completa la transición (todas las vistas se han eliminado de la jerarquía. Sin embargo, establecer la propiedad 'modalPresentationStyle' en '.fullscreen' SÍ funciona. Saludos.
Womble
Probé la versión Obj-C de la implementación de Swift de Mark y gwinyai en mi proyecto. Desafortunadamente, ninguno de ellos está funcionando como se esperaba. Estoy usando Xcode 11.1 y el objetivo de compilación es iOS 13.0, lo probé tanto en el dispositivo como en el simulador. En mi caso, mi configuración básica es una vista de colección y cuando tocas una celda pasará a una vista detallada con animación. Sin embargo, funciona totalmente bien si estoy usando la animación de transición predeterminada. El CV de presentación no desaparecerá cuando reanude la vista desde los detalles.
infinity_coding7
8

En iOS 8, necesita crear un UIPresentationController e implementar el método siguiente, en UIViewControllerTransitioningDelegate.

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

Pide a su delegado que utilice el controlador de presentación personalizado para administrar la jerarquía de vista al presentar un controlador de vista.

Valor devuelto:

El controlador de presentación personalizado para administrar la presentación modal.

Discusión:

Cuando presenta un controlador de vista utilizando el estilo de presentación UIModalPresentationCustom, el sistema llama a este método y solicita el controlador de presentación que administra su estilo personalizado. Si implementa este método, utilícelo para crear y devolver el objeto controlador de presentación personalizado que desea usar para administrar el proceso de presentación.

Si no implementa este método, o si su implementación de este método devuelve nil, el sistema usa un objeto controlador de presentación predeterminado. El controlador de presentación predeterminado no agrega vistas ni contenido a la jerarquía de vistas.

Disponibilidad Disponible en iOS 8.0 y posterior.

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:

initWithPresentedViewController:presented presentingViewController:presenting

Antes se presentaba y luego se presentaba. Simplemente cámbielos y debería funcionar.

Paulo Faria
fuente
Lo siento por no ver el video vinculado, pero no creo que necesite un UIPresentationController personalizado a menos que desee una presentación no estándar después de que se complete la animación, como una vista circular presentada. Si solo desea una animación diferente, implementar UIViewControllerAnimatedTransitioning debería ser suficiente, según mi conocimiento limitado.
Vaddadi Kartick
7

en lugar de [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; simplemente agregue: [inView addSubview: toViewController.view];

if (self.presenting) {

    [transitionContext.containerView addSubview:toViewController.view];
    // your code

} else {
    // your code
}

Puedes ver un ejemplo aquí: enlace y funciona en iOS 7 y iOS 8

CarlosGz
fuente
Esta debería ser la respuesta aceptada para hacer un tipo de animación UIModalPresentationStyleCustom, ya que no es necesario agregar fromViewController al containerView. Solo necesita agregar toViewController durante la animación de presentación.
Scott Kaiser
Esto es muy útil, en realidad
Dmitry Bondarev
7

Aquí hay una versión Objective C de la solución de Ash.

// my attempt at obj-c version of Ash's fix
UIView *theToView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
[[[UIApplication sharedApplication] keyWindow] addSubview:theToView];
[transitionContext completeTransition:YES]

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!

vichudson1
fuente
5

Encontré que esto funcionó bien para Obj-C:

    [transitionContext completeTransition:YES];
    if(![[UIApplication sharedApplication].keyWindow.subviews containsObject:toViewController.view]) {
        [[UIApplication sharedApplication].keyWindow addSubview:toViewController.view];
    }

Parece funcionar bien tanto en ios7 como en ios8.

Lleno de cañas
fuente
5

Encontré que viewForKey:UITransitionContextToViewKeydevuelve 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:YESse llama. Entonces, si viewForKey:UITransitionContextToViewKeydevuelve nil, me caigo y hago toVC.viewun 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.

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    // Get the 'from' and 'to' views/controllers.
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    BOOL hasViewForKey = [transitionContext respondsToSelector:@selector(viewForKey:)]; // viewForKey is iOS8+.
    UIView *fromView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextFromViewKey] :
        fromVC.view;
    UIView *toView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextToViewKey] :
        toVC.view;

    // iOS8 has a bug where viewForKey:to is nil: http://stackoverflow.com/a/24589312/59198
    // The workaround is: A) get the 'toView' from 'toVC'; B) manually add the 'toView' to the container's
    // superview (eg the root window) after the completeTransition call.
    BOOL toViewNilBug = !toView;
    if (!toView) { // Workaround by getting it from the view.
        toView = toVC.view;
    }
    UIView *container = [transitionContext containerView];
    UIView *containerSuper = container.superview; // Used for the iOS8 bug workaround.

    // Perform the transition.
    toView.frame = container.bounds;
    [container insertSubview:toView belowSubview:fromView];
    [UIView animateWithDuration:kDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
        fromView.frame = CGRectOffset(container.bounds, 0, CGRectGetHeight(container.bounds));
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];

        if (toViewNilBug) {
            [containerSuper addSubview:toView];
        }
    }];
}
Chris
fuente
3

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.

Chris
fuente
2

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:

  1. Cree una subclase de UIPresentationController. Anule shouldRemovePresentersView a falso de la siguiente manera:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. 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:

    let newVC = mainStoryboard.instantiateViewController(withIdentifier: "newVC") as! NewViewController 
    
    newVC.transitioningDelegate = self
    
    newVC.modalPresentationStyle = UIModalPresentationStyle.custom
    
    newVC.modalPresentationCapturesStatusBarAppearance = true //optional
    
    present(newVC, animated: true, completion: nil)
  3. 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:

    extension CurrentViewController: UIViewControllerTransitioningDelegate {
    
    //this is where you implement animationController(forPresented) and animationController(forDismissed) methods
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    
    return ModalPresentationController(presentedViewController: presented, presenting: source)
    
    }
    }

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.

gwinyai
fuente
¡Este es un gran ejemplo de cómo hacer una presentación modal personalizada en Swift 3! ¡Gracias @gwinyai! Me quedé muy atascado en esto hasta que encontré un ejemplo que mostraba la nueva API de Swift 3 presentationController(forPresented presented UIViewController,... porque la API de Swift anterior no molestó al cumplidor, pero no recibió la llamada.
Natalia
2

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 modalPresentationStylea .overFullScreen. Esto es correcto, .overCurrentContexttambié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.

Jordan Smith
fuente
1
Configuré el estilo de presentación .overCurrentContext antes de la carga de la vista (en el initcontrolador de vista) y el problema aún ocurre
ricardopereira
1

El 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.

malhal
fuente
Por alguna razón, esto no parece permitir la interacción con la vista de abajo, donde lo hizo UIModalPresentationCurrentContext en iOS 7. ¿Alguna idea?
Christopher Wirt
Mmmm para mí en iOS 10, .overCurrentContext da como resultado este error, pero .fullscreen no. Vine aquí con la esperanza de una solución para el uso de .overCurrentContext, pero hasta ahora nada parece funcionar en iOS 10, excepto tal vez subclasificar UIPresentationController ...
Natalia
0

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

transitionContext.completeTransition(true)

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:

transitionContext.viewController(forKey: .to)?.view
transitionContext.viewController(forKey: .from)?.view

Directamente de manera:

transitionContext.view(forKey: .to)
transitionContext.view(forKey: .from)

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.

infinity_coding7
fuente
0

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

  1. cambie el .modalPresentationStyledel childVC presentado por parentVC del predeterminado .automatica .fullscreen.
  2. Luego cambió el .modalPresentationStylede contentVC a .fullscreentambié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 .overCurrentContexto 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.

arvinq
fuente
-3

agrega un controlador de vista como hijo de otro controlador de vista.

[self addChildViewController:childViewController];                 

verifique y avíseme.

Rushabh
fuente
no obtengo, ¿puedes describirlo usando codificación?
NiravPatel
consulte esta documentación de Apple developer.apple.com/library/ios/featuredarticles/…
Rushabh
esto de ninguna manera responde a la pregunta. Los ChildViewControllers no están involucrados en ninguna parte de las transiciones personalizadas, son un tema completamente diferente.
Andras M.