descargar caracteristicas ios ios7

ios - caracteristicas - Animación de transición personalizada que no llama a los métodos del ciclo de vida de VC en el despido



ios 9 (6)

Así que construí una animación de transición de presentación personalizada y todo parece estar funcionando muy bien, excepto que los métodos de ciclo de vida del controlador de vista no están siendo cancelados.

Antes de presentar el controlador, uso el estilo UIModalPresentationCustom para mantener el VC de presentación en la jerarquía de vistas, pero una vez que descarto el VC presentado, viewWillAppear y viewDidAppear no aparecen en mi controlador de presentación. ¿Me estoy perdiendo un paso al que necesito llamar explícitamente para que esos métodos se activen? Sé que llamar manualmente a esos métodos no es la solución correcta.

Aquí está mi código de animación de despido. Básicamente estoy animando una vista de superposición de formulario para reducir el tamaño de una celda de vista de colección al momento del despido.

- (void)_animateDismissingTransitionWithContext:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UICollectionView *destinationCollectionView = toCollectionViewController.collectionView; UICollectionViewCell *destinationCollectionViewCell = [self _destinationCellFromContext:transitionContext]; UIView *containerView = transitionContext.containerView; // Calculate frames CGRect startFrame = fromEventDetailViewController.detailContainerView.frame; CGRect endFrame = [destinationCollectionView convertRect:destinationCollectionViewCell.frame toView:containerView]; // Add overlay UIView *overlayView = [UIView new]; overlayView.backgroundColor = [UIColor overlayBackground]; overlayView.frame = containerView.bounds; overlayView.alpha = 1.0f; [containerView addSubview:overlayView]; // Add fake detail container view UIView *fakeContainerView = [UIView new]; fakeContainerView.backgroundColor = fromEventDetailViewController.detailContainerView.backgroundColor; fakeContainerView.frame = startFrame; [containerView addSubview:fakeContainerView]; // Hide from view controller fromEventDetailViewController.view.alpha = 0.0f; [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0f usingSpringWithDamping:0.75f initialSpringVelocity:0.2f options:UIViewAnimationOptionCurveEaseOut animations:^{ fakeContainerView.frame = endFrame; fakeContainerView.backgroundColor = [UIColor eventCellBackground]; overlayView.alpha = 0.0f; } completion:^(BOOL finished) { [fromEventDetailViewController.view removeFromSuperview]; [overlayView removeFromSuperview]; [fakeContainerView removeFromSuperview]; [transitionContext completeTransition:YES]; }]; }


Ah, esta es una presentación modal. No creo que se llame a viewWillAppear y viewDidAppear con una transición personalizada utilizando el método, ya que la vista aún está técnicamente activa en la jerarquía de vistas. Sugeriría usar la delegación aquí como lo haría normalmente con un modal presentado.

Crear protocolo de delegado en el CV presentado. Cree un método de delegado que pueda llamarse desde el CV de presentación. Al presentar la superposición, establezca el CV de presentación como el delegado. Luego, llame a ese método de delegado desde el CV presentado. Luego, puede llamar a cualquier tipo de acciones desde el VC de presentación antes de llamar a dismissViewController

En su superposición (ModalViewController.h):

@protocol ModalViewDelegate <NSObject> -(void)didDismissModalView; @end @interface ModalViewController : UIViewController @property(strong, nonatomic) id <ModalViewDelegate> delegate;

En su ModalViewController.m, llame a un método que llame a su método de delegado:

- (void)dismissModal{ [self.delegate didDismissModalView]; }

En su archivo de presentación de VC h: (PresentingViewController.h), haga que esta clase se ajuste a su protocolo de delegado modal:

@interface PresentingViewController : UIViewController <ModalViewDelegate>

En su presentación de CV, al presentar el modal:

... ModalViewController *modalViewController = [[ModalViewController alloc] init]; modalViewController.delegate = self; //the makes the presenting VC the delegate [self presentViewController:modalViewController animated:YES completion:nil]; ...

Finalmente, en su presentación de VC, cuando desee realizar algunas acciones antes de descartar el modal, implemente el método ModalViewDelegate:

- (void)didDismissModalView{ //DO SOME COOL STUFF, SET UP STUFF HERE, UPDATE UI, ETC //Then dismiss the modal [self dismissViewControllerAnimated:YES completion:^{ //Do more cool stuff }]; }

Todo esto funcionará con su código de transición personalizado actual, pero le dará más control sobre lo que sucede antes de que se elimine el modal / overlay. El delegado es una cosa hermosa.

Además, esto mantendrá este código de animación separado del código para otra funcionalidad, que es un IMO un poco más limpio.


Después de muchas discusiones con este problema, encontré que la mejor solución que funciona en ios7 y ios8 es dejar modalPresentationStyle = UIModalPresentationFullScreen lugar de UIModalPresentationCustom como sugieren los documentos.

Si hago esto además de configurar el dato de transitioningDelegate a mi delegado, todavía respeta mi transición y los métodos will / diddisappear se activan en el controlador de vista ''desde''. También: no hay problemas de rotación de presente, luego rotar y luego descartar para arrancar.


Es incorrecto llamar a los métodos de aparición / finalización en el proceso de animación. ¿Qué pasó si presentas ver controlador sin animación? A la derecha, la presentación del controlador de vista no recibirá devoluciones de llamada de apariencia. Debe implementar UIPresentationController personalizado y llamar a los métodos de inicio / finalización de la llamada. Aquí muestra:

@interface CustomPresentationController : UIPresentationController @end @implementation CustomPresentationController - (void)presentationTransitionWillBegin { [self.presentingViewController beginAppearanceTransition:NO animated:NO]; } - (void)presentationTransitionDidEnd:(BOOL)completed { [self.presentingViewController endAppearanceTransition]; } - (void)dismissalTransitionWillBegin { [self.presentingViewController beginAppearanceTransition:YES animated:NO]; } - (void)dismissalTransitionDidEnd:(BOOL)completed { [self.presentingViewController endAppearanceTransition]; } @end


La respuesta de @John Tracids ''solucionó mi problema. Gracias John!

Pero me gustaría extender un poco la respuesta.

Si está presentando la instancia de modalPresentationStyle = .custom con modalPresentationStyle = .custom (objc UIModalPresentationCustom ) para mantener los métodos del ciclo de vida del controlador de vista que se está llamando, debe administrar la apariencia del controlador de vista de forma explícita. Para hacerlo, simplemente llame a beginAppearanceTransition antes de animation y endAppearanceTransition en el bloque de finalización de animación.

También puede pasar a su clase de animador de transición la subclase UIPresentationController personalizada con el valor invalidado shouldRemovePresentersView eliminar los shouldRemovePresentersView devolviendo true sin llamar a beginAppearanceTransition

// Swift 4

ponga esto en su clase UIViewControllerAnimatedTransitioning personalizada antes de la animación

fromViewController.beginAppearanceTransition(false, animated: true) toViewController.beginAppearanceTransition(true, animated: true) UIView.animate(withDuration: animationDuration, animations: { // animation logic… }) { finished in fromViewController.endAppearanceTransition() toViewController.endAppearanceTransition() let transitionSuccess = !transitionContext.transitionWasCancelled transitionContext.completeTransition(transitionSuccess) } // UIPresentationController subclass class PresentationController: UIPresentationController { override var shouldRemovePresentersView: Bool { return true } }


Otra solución podría ser utilizando beginAppearanceTransition: y endAppearanceTransition:. Según la documentación:

Si está implementando un controlador de contenedor personalizado, use este método para decirle al niño que sus vistas están a punto de aparecer o desaparecer. No invoque viewWillAppear :, viewWillDisappear :, viewDidAppear :, o viewDidDisappear: directamente.

Aquí es cómo los usé:

- (void)animationEnded:(BOOL)transitionCompleted { if (!transitionCompleted) { _toViewController.view.transform = CGAffineTransformIdentity; } else { [_toViewController endAppearanceTransition]; } } - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; [toViewController beginAppearanceTransition:YES animated:YES]; // ... other code }

Pero todavía considero extraño que la presentación modal personalizada no haga esto.


Si está utilizando UIModalPresentationCustom , debe proporcionar la clase UIPresentationController personalizada, y si desea usar a los llamadores del ciclo de vida de ViewController, debe anular shouldRemovePresentersView y devolver YES .

Si desea mantener a los presentadores y aún tiene la devolución de llamada del ciclo de vida de ViewControlelr, puede anular el método privado _shouldDisablePresentersAppearanceCallbacks y devolver NO en su clase personalizada UIPresentationController .