iphone - animate - ¿Anima a los controladores de cambio de vista sin usar la pila del controlador de navegación, las subvistas o los controladores modales?
uiview animate swift 4 (6)
Como me topé con este problema exacto y probé variaciones en todas las respuestas preexistentes al éxito limitado, publicaré cómo finalmente lo resolví:
Como se describe en esta publicación sobre segues personalizados , en realidad es realmente fácil hacer segues personalizados. También son muy fáciles de conectar en Interface Builder, mantienen las relaciones en IB visibles, y no requieren mucho soporte por parte de los controladores de vista fuente / destino de segue.
La publicación vinculada anteriormente proporciona el código de iOS 4 para reemplazar el controlador de vista superior actual en la pila de navigationController por uno nuevo con una animación de deslizamiento desde arriba.
En mi caso, quería que sucediera un cambio de reemplazo similar, pero con una transición de FlipFromLeft
. También solo necesitaba soporte para iOS 5+. Código:
De RAFlipReplaceSegue.h:
#import <UIKit/UIKit.h>
@interface RAFlipReplaceSegue : UIStoryboardSegue
@end
De RAFlipReplaceSegue.m:
#import "RAFlipReplaceSegue.h"
@implementation RAFlipReplaceSegue
-(void) perform
{
UIViewController *destVC = self.destinationViewController;
UIViewController *sourceVC = self.sourceViewController;
[destVC viewWillAppear:YES];
destVC.view.frame = sourceVC.view.frame;
[UIView transitionFromView:sourceVC.view
toView:destVC.view
duration:0.7
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished)
{
[destVC viewDidAppear:YES];
UINavigationController *nav = sourceVC.navigationController;
[nav popViewControllerAnimated:NO];
[nav pushViewController:destVC animated:NO];
}
];
}
@end
Ahora, mantenga presionada la tecla de control para configurar cualquier otro tipo de segue, luego conviértalo en un segue personalizado y escriba el nombre de la clase segue personalizada, et voilà!
NavigationControllers tiene pilas de ViewController para administrar, y transiciones de animación limitadas.
Agregar un controlador de vista como una sub-vista a un controlador de vista existente requiere pasar eventos al controlador de subvista, lo cual es difícil de manejar, cargado con pequeñas molestias y en general se siente como un mal truco cuando se implementa (Apple también recomienda haciendo esto).
La presentación de un controlador de vista modal coloca nuevamente un controlador de vista encima de otro y, aunque no tiene los problemas de suceso descritos anteriormente, en realidad no ''intercambia'' el controlador de vista, sino que lo apila.
Los guiones gráficos están limitados a iOS 5 y son casi ideales, pero no se pueden usar en todos los proyectos.
¿Puede alguien presentar un EJEMPLO DE CÓDIGO SÓLIDO en una forma de cambiar los controladores de vista sin las limitaciones anteriores y permite transiciones animadas entre ellos?
Un ejemplo cercano, pero sin animación: cómo usar múltiples controles de vista personalizados iOS sin un controlador de navegación
Editar: el uso del controlador Nav está bien, pero es necesario que haya estilos de transición animados (no simplemente los efectos de diapositivas). El controlador de visualización que se muestra debe intercambiarse por completo (no apilarse). Si el segundo controlador de vista debe eliminar otro controlador de vista de la pila, entonces no está lo suficientemente encapsulado.
Edición 2: iOS 4 debería ser el sistema operativo base para esta pregunta, debería haber aclarado eso al mencionar guiones gráficos (arriba).
De acuerdo, sé que la pregunta dice sin usar un controlador de navegación, pero no hay razón para no hacerlo. OP no respondía a los comentarios a tiempo para que me fuera a dormir. No me votes. :)
A continuación, le mostramos cómo abrir el controlador de vista actual y voltearlo a un nuevo controlador de vista usando un controlador de navegación:
UINavigationController *myNavigationController = self.navigationController;
[[self retain] autorelease];
[myNavigationController popViewControllerAnimated:NO];
PreferencesViewController *controller = [[PreferencesViewController alloc] initWithNibName:nil bundle:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.65];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:myNavigationController.view cache:YES];
[myNavigationController pushViewController:controller animated:NO];
[UIView commitAnimations];
[controller release];
Luché con este durante mucho tiempo, y uno de mis problemas aparece here , no estoy seguro de si has tenido ese problema. Pero esto es lo que recomendaría si funcionara con iOS 4.
En primer lugar, crea una nueva clase NavigationController
. Aquí es donde haremos todo el trabajo sucio: otras clases podrán llamar "limpiamente" a métodos de instancia como pushViewController:
y pushViewController:
. En tu .h
:
@interface NavigationController : UIViewController {
NSMutableArray *childViewControllers;
UIViewController *currentViewController;
}
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL))completion;
- (void)addChildViewController:(UIViewController *)childController;
- (void)removeChildViewController:(UIViewController *)childController;
La matriz de controles de vista secundarios servirá como una tienda para todos los controladores de vista en nuestra pila. currentController
automáticamente todos los códigos de rotación y cambio de tamaño desde la vista de NavigationController
al currentController
.
Ahora, en nuestra implementación:
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL))completion
{
currentViewController = [toViewController retain];
// Put any auto- and manual-resizing handling code here
[UIView animateWithDuration:duration animations:animations completion:completion];
[fromViewController.view removeFromSuperview];
}
- (void)addChildViewController:(UIViewController *)childController {
[childViewControllers addObject:childController];
}
- (void)removeChildViewController:(UIViewController *)childController {
[childViewControllers removeObject:childController];
}
Ahora puede implementar su propio pushViewController:
popViewController
y popViewController
, utilizando estas llamadas a métodos.
Buena suerte, y espero que esto ayude!
Puede usar el nuevo sistema de contención viewController de Apple. Para obtener información más detallada, consulte el video de la sesión de la WWDC 2011 "Implementación de la contención de UIViewController
".
Nuevo en iOS5, la contención de UIViewController
permite tener un control de vista principal y una cantidad de controles de vista secundarios que están contenidos en él. Así es como funciona el UISplitViewController. Al hacer esto, puede apilar los controladores de vista en un padre, pero para su aplicación particular, solo está usando el elemento principal para administrar la transición de un controlador de vista visible a otro. Esta es la forma de hacer las cosas aprobada por Apple y animar desde un niño viewController es sencillo. ¡Además, puedes usar todas las diferentes transiciones UIViewAnimationOption
!
Además, con UIViewContainment, no tiene que preocuparse, a menos que lo desee, del desorden de la administración de los viewControllers secundarios durante los eventos de orientación. Simplemente puede usar lo siguiente para asegurarse de que parentViewController reenvíe los eventos de rotación a los viewControllers secundarios.
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers{
return YES;
}
Puede hacer lo siguiente o similar en el método viewDidLoad de su padre para configurar el primer childViewController:
[self addChildViewController:self.currentViewController];
[self.view addSubview:self.currentViewController.view];
[self.currentViewController didMoveToParentViewController:self];
[self.currentViewController.swapViewControllerButton setTitle:@"Swap" forState:UIControlStateNormal];
luego, cuando necesite cambiar el niño viewController, llame algo de la siguiente manera dentro del padre ViewController:
-(void)swapViewControllers:(childViewController *)addChildViewController:aNewViewController{
[self addChildViewController:aNewViewController];
__weak __block ViewController *weakSelf=self;
[self transitionFromViewController:self.currentViewController
toViewController:aNewViewController
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:nil
completion:^(BOOL finished) {
[aNewViewController didMoveToParentViewController:weakSelf];
[weakSelf.currentViewController willMoveToParentViewController:nil];
[weakSelf.currentViewController removeFromParentViewController];
weakSelf.currentViewController=[aNewViewController autorelease];
}];
}
Publiqué un proyecto de ejemplo completo aquí: https://github.com/toolmanGitHub/stackedViewControllers . Este otro proyecto muestra cómo usar la contención de UIViewController
en algunos tipos de input viewController que no ocupan toda la pantalla. Buena suerte
EDITAR: Nueva respuesta que funciona en cualquier orientación. La respuesta original solo funciona cuando la interfaz está en orientación vertical. Esta es una vista de b / c animaciones de transición que reemplazan una vista con una vista diferente debe aparecer con vistas al menos un nivel debajo de la primera vista agregada a la ventana (por ejemplo, window.rootViewController.view.anotherView
).
Implementé una clase de contenedor simple que llamé TransitionController
. Puede encontrarlo en https://gist.github.com/1394947 .
Como un aparte, prefiero la implementación en una clase separada b / c es más fácil de reutilizar. Si no quiere eso, puede simplemente implementar la misma lógica directamente en su delegado de aplicación eliminando la necesidad de la clase TransitionController
. La lógica que necesitarías sería la misma sin embargo.
Úselo de la siguiente manera:
En tu aplicación delegada
// add a property for the TransitionController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
MyViewController *vc = [[MyViewContoller alloc] init...];
self.transitionController = [[TransitionController alloc] initWithViewController:vc];
self.window.rootViewController = self.transitionController;
[self.window makeKeyAndVisible];
return YES;
}
Para hacer la transición a un nuevo controlador de vista desde cualquier controlador de vista
- (IBAction)flipToView
{
anotherViewController *vc = [[AnotherViewController alloc] init...];
MyAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate.transitionController transitionToViewController:vc withOptions:UIViewAnimationOptionTransitionFlipFromRight];
}
EDITAR: Respuesta original a continuación - solo funciona para la orientación del retrato
Hice las siguientes suposiciones para este ejemplo:
Usted tiene un controlador de vista asignado como el controlador
rootViewController
de su ventanaCuando cambia a una nueva vista, desea reemplazar el viewController actual con viewController que posee la nueva vista. En cualquier momento, solo el viewController actual está vivo (por ejemplo, alojado).
El código se puede modificar fácilmente para que funcione de manera diferente, el punto clave es la transición animada y el controlador de vista única. Asegúrese de no retener un controlador de vista en ningún lugar fuera de asignarlo a window.rootViewController
.
Código para animar la transición en el delegado de la aplicación
- (void)transitionToViewController:(UIViewController *)viewController
withTransition:(UIViewAnimationOptions)transition
{
[UIView transitionFromView:self.window.rootViewController.view
toView:viewController.view
duration:0.65f
options:transition
completion:^(BOOL finished){
self.window.rootViewController = viewController;
}];
}
Ejemplo de uso en un controlador de vista
- (IBAction)flipToNextView
{
AnotherViewController *anotherVC = [[AnotherVC alloc] init...];
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate transitionToViewController:anotherVC
withTransition:UIViewAnimationOptionTransitionFlipFromRight];
}
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UINavigationController *viewController = (UINavigationController *)[storyboard instantiateViewControllerWithIdentifier:@"storyBoardIdentifier"];
viewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:viewController animated:YES completion:nil];
Prueba este código
Este código da Transición desde un controlador de vista a otro controlador de vista que tiene un controlador de navegación.