2010-07-12 17 views
20

Así que tenga una pila con tres controladores de vista donde A es raíz, B es el primer controlador de vista modal y C es la tercera vc modal. Me gustaría ir de C a A de una vez. He intentado this solution to dismiss. Lo hace trabajo pero no de manera correcta. Ahí es cuando se descarta el último controlador de vista, mostrará brevemente el segundo controlador de vista antes de que se muestre el primero. Lo que estoy buscando es una forma de pasar del tercer vc al primero de una animación agradable sin notar la segunda vista. Cualquier ayuda sobre esto es muy apreciada.¿Desea omitir varios controladores de vista modal a la vez?

+0

Una manera más genérica de descartar más de un controlador de vista modal es [aquí] (https://stackoverflow.com/a/44583711/1151916) – Ramis

Respuesta

20

Asegúrese de llamar una sola vez al dismissModalViewControllerAnimated:.

He encontrado que pedir que se descarte cada controlador de vista modal apilado causará que ambos se animen.

tiene: A =modal> B =modal> C

Sólo debe llamar [myViewControllerA dismissModalViewControllerAnimated:YES]

Si utiliza [myViewControllerB dismissModalViewControllerAnimated:YES], se despedirá C, y no B. En condiciones normales (no apiladas) uso, se descartaría B (debido a la cadena de respuesta burbujeando el mensaje hasta A). En el escenario apilado que describe, B es un controlador de vista principal y esto tiene prioridad sobre ser un controlador de vista modal.

+7

Bueno, ahora uso: [[[self parentViewController] parentViewController] dismissModalViewControllerAnimated: YES]; Eso usaría el controlador de vista raíz. Sin embargo, todavía muestra el segundo vc por segundo. – sebrock

+0

Ah, y debería decir que utilizo la plantilla de utilidad y la segunda vc es la vista flipside. El tercero es un vc modal instanciado desde el otro lado. – sebrock

+1

NOTA: en iOS5 esto cambió a "presentingViewController" http://game4mob.com/index.php/jawbreaker/66-dismiss-modal-view-in-ios5-sdk –

-5

Lo que quiere usar es popToRootViewControllerAnimated:. Te lleva al controlador raíz sin mostrar todos los intermedios.

+1

Esa es una gran solución si A es la raíz de un 'UINavigationController' – ohhorob

+1

Oh sí. Me desperté, así que no entendí eso. – lucius

0

Puede descartar estos modalViewControllers en su control raízViewController.

UIViewController *viewController = yourRootViewController; 

    NSMutableArray *array = [NSMutableArray array]; 
    while (viewController.modalViewController) { 
     [array addObject:viewController]; 
     viewController = viewController.modalViewController; 
    } 

    for (int i = 0; i < array.count; i++) { 
     UIViewController *viewController = array[array.count-1-i]; 
     [viewController dismissModalViewControllerAnimated:NO]; 
    } 
3

Aunque la respuesta aceptada hizo el trabajo para mí, puede ser obsoleta ahora y dejó una animación de aspecto extraño en el que el modal superior desaparecería inmediatamente y la animación estaría en el modalview trasera. Probé muchas cosas para evitar esto y terminé teniendo que usar un truco para que se vea bien. Nota: (sólo probado en iOS8 +, pero debería funcionar iOS7 +)

Básicamente, viewControllerA crea una UINavigationController con viewControllerB como el rootview y la presenta de forma modal.

// ViewControllerA.m 
- (void)presentViewB { 
    ViewControllerB *viewControllerB = [[ViewControllerB alloc] init]; 
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewControllerB]; 

    navigationController.modalPresentationStyle = UIModalPresentationFormSheet; 
    [self presentViewController:navigationController animated:YES completion:nil]; 
} 

Ahora en viewControllerB vamos a presentar viewControllerC la misma manera, pero después de lo presentamos, nos vamos a poner una instantánea de viewControllerC sobre la capa de vista de control de navegación viewControllerB 's. Entonces, cuando viewControllerC desaparezca durante el despido, no veremos el cambio y la animación se verá hermosa.

//ViewControllerB.m 
- (void)presentViewC { 
    ViewControllerC *viewControllerC = [[ViewControllerC alloc] init]; 

    // Custom presenter method to handle setting up dismiss and snapshotting 
    // I use this in a menu that can present many VC's so I centralized this part. 
    [self presentViewControllerForModalDismissal:viewControllerC]; 
} 

A continuación se presentan mis funciones de ayuda que se utilizan para presentar la vista y manejar la denegación. Una cosa a tener en cuenta, estoy usando Purelayout para agregar restricciones de diseño automático. Puede modificar esto para añadirlos manualmente o conseguir Purelayout en https://github.com/PureLayout/PureLayout

#pragma mark - Modal Presentation Helper functions 
- (void)presentViewControllerForModalDismissal:(UIViewController*)viewControllerToPresent { 
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewControllerToPresent]; 
    navigationController.modalPresentationStyle = UIModalPresentationFormSheet; 

    // Ensure that anything we are trying to present with this method has a dismissBlock since I don't want to force everything to inherit from some base class. 
    NSAssert([viewControllerToPresent respondsToSelector:NSSelectorFromString(@"dismissBlock")], @"ViewControllers presented through this function must have a dismissBlock property of type (void)(^)()"); 
    [viewControllerToPresent setValue:[self getDismissalBlock] forKey:@"dismissBlock"]; 

    [self presentViewController:navigationController animated:YES completion:^{ 
     // We want the presented view and this modal menu to dismiss simultaneous. The animation looks weird and immediately becomes the menu again when dismissing. 
     // So we are snapshotting the presented view and adding it as a subview so you won't see the menu again when dismissing. 
     UIView *snapshot = [navigationController.view snapshotViewAfterScreenUpdates:NO]; 
     [self.navigationController.view addSubview:snapshot]; 
     [snapshot autoPinEdgesToSuperviewEdges]; 
    }]; 
} 

- (void(^)()) getDismissalBlock { 
    __weak __typeof(self) weakSelf = self; 
    void(^dismissBlock)() = ^{ 
     __typeof(self) blockSafeSelf = weakSelf; 
     [blockSafeSelf.navigationController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 
    }; 

    return dismissBlock; 
} 

Ahora sólo tenemos que asegurarnos de tener la dismissBlock define como una propiedad en ViewControllerC.h (puede reemplazar obviamente toda esta parte con los métodos de delegado u otros patrones de diseño igual de emocionantes, la parte importante es manejar el despido a nivel viewControllerB)

// ViewControllerC.h 
@interface ViewControllerC : UIViewController 
@property (nonatomic, copy) void (^dismissBlock)(void); 
@end 

//ViewControllerC.m 
// Make an method to handle dismissal that is called by button press or whatever logic makes sense. 
- (void)closeButtonPressed { 
    if (_dismissBlock) {// If the dismissblock property was set, let the block handle dismissing 
     _dismissBlock(); 
     return; 
    } 

    // Leaving this here simply allows the viewController to be presented modally as the base as well or allow the presenter to handle it with a block. 
    [self dismissViewControllerAnimated:YES completion:nil]; 
} 

Espero que esto ayude, programación feliz :)

+0

upvote para una solución de trabajo, pero esto es simplemente una locura (en comparación con su beneficio) –

+1

Es, pero literalmente no es una buena solución de trabajo que es fácil y se ve bien. Estaba frustrado porque la manzana no tenía una buena manera de manejar esto. Esperemos que con el nuevo lanzamiento este otoño. – johnrechd

+0

Absolutamente cierto. Fui de otra manera y descarté viewControllers uno después del otro (no es una solución al problema, pero funciona y no es tan feo) –

Cuestiones relacionadas