2012-08-05 19 views
13

Estoy escribiendo una aplicación simple que tiene 3 controladores de vista. El controlador de vista raíz es item listing, vista de tabla básica. Desactivado de este controlador de vista, presiono dos controles de vista diferentes en función de la interacción del usuario: un controlador de vista create item o un controlador de vista view item.¿Cómo volver al control de la vista raíz pero luego presionar a una vista diferente?

Por lo tanto, los guiones del guión gráfico simplemente se ven como una V, o algo así.

En mi controlador de vista create item, me gustaría que vuelva a aparecer en el controlador de vista raíz cuando el usuario crea un nuevo elemento, pero luego presiono el controlador view item para poder ver el elemento recién creado.

Parece que no puedo hacer que esto funcione. Es bastante fácil regresar al controlador de vista raíz, pero no puedo presionar ese controlador view item.

¿Alguna idea? He pegado mi código, a continuación. La función pop funciona, pero la nueva vista nunca aparece.

- (void) onSave:(id)sender { 

    CLLocation *currentLocation = [[LocationHelper sharedInstance] currentLocation]; 

    // format the thread object dictionary 
    NSArray* location = @[ @(currentLocation.coordinate.latitude), @(currentLocation.coordinate.longitude) ]; 
    NSDictionary* thread = @{ @"title": _titleField.text, @"text": _textField.text, @"author": @"mustached-bear", @"location": location }; 

    // send the new thread to the api server 
    [[DerpHipsterAPIClient sharedClient] postPath:@"/api/thread" 
             parameters:thread 
              success:^(AFHTTPRequestOperation *operation, id responseObject) { 

               // init thread object 
               Thread *thread = [[Thread alloc] initWithDictionary:responseObject]; 

               // init view thread controller 
               ThreadViewController *viewThreadController = [[ThreadViewController alloc] init]; 
               viewThreadController.thread = thread; 

               [self.navigationController popToRootViewControllerAnimated:NO]; 
               [self.navigationController pushViewController:viewThreadController animated:YES]; 

              } 
              failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

               [self.navigationController popToRootViewControllerAnimated:YES]; 

              }]; 

} 
+0

No crearía diferentes controladores de vista para "Crear elemento" y "Ver elemento". Es cierto que es posible que desee ver el elemento después de crearlo, pero siempre existe otra posibilidad de que su usuario desee EDITAR el elemento después de verlo. Sería más fácil diseñar un controlador de vista para permitir crear, ver y editar en una sola vista. La mayoría de las aplicaciones lo diseñan de esta manera. Ahorre su tiempo segueing alrededor. – Rick

Respuesta

6

Una manera fácil de lograr lo que quieres hacer es construir una lógica simple en sus principales controladores de vista de la raíz - (void) Método viewWillAppear y utilizar una devolución de llamada delegado a darle la vuelta al interruptor de la lógica. básicamente una "referencia posterior" al controlador raíz. aquí hay un ejemplo rápido.

controlador principal de la raíz (considere este controlador a) - así llamarlo controllerA establecer una propiedad para realizar un seguimiento de la situación del salto

@property (nonatomic) BOOL jumpNeeded; 

configuración cierta lógica en

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    self.jumpNeeded ? NSLog(@"jump needed") : NSLog(@"no jump needed"); 

    if (self.jumpNeeded) { 
     NSLog(@"jumping"); 
     self.jumpNeeded = NO; 
     [self performSegueWithIdentifier:@"controllerC" sender:self]; 
    } 
} 

Ahora, en su controlador raíz principal, cuando se selecciona una fila de vista de tabla, haga algo como esto al presionar al controladorB en su tabla Vista seleccionó el método

[self [email protected]"controllerB" sender:self]; 

continuación, poner en práctica su preparación para el método segue

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 

    //setup controller B 
    if([segue.identifier isEqualTo:@"controllerB"]){ 
    ControllerB *b = segue.destinationViewController; 
    b.delegate = self; //note this is the back reference 
    } 

    //implement controller c here if needed 
} 

Ahora pasar a controllerB es necesario establecer una propiedad llamada "delegado" para mantener la referencia posterior y hay que importar el archivo de cabecera de el controlador de la raíz

#import "controllerA" 

@property (nonatomic,weak) controllerA *delegate; 

continuación, justo antes de que el pop de nuevo a controllerA, establece el indicador

self.delegate.jumpNeeded = YES; 
    [self.navigationController popViewControllerAnimated:YES]; 

y eso es todo. No tiene que hacer nada con controllerC. Hay algunas otras formas de hacerlo, pero esto es bastante directo para sus necesidades. Espero que funcione para usted.

+0

Elegí esta como la respuesta, porque los delegados fueron la ruta que terminé yendo. Sin embargo, abandoné el push segue all-together y seguí una transición modal para la vista 'create item'. – Ryan

+0

Me alegro de que los consejos te ayudaron en una dirección que funcionó para ti. ¡la mejor de las suertes! – CocoaEv

0

No creo que esto sea posible porque al volver atrás se desasignará todo.

Creo que una mejor manera es poner sus datos en una clase de singleton modelo, pasar al controlador de visualización de raíz y escuchar que el pop finalice. Luego, verifica si hay algunos datos almacenados en el modelo para que sepas si deberías presionar un nuevo controlador de visualización.

6

creo
[self.navigationController pushViewController:viewThreadController animated:YES]; utiliza una NavigationController diferente de la declaración antes de eso. Porque después de hacer estallar a la vista raíz Controlador de que pierda el control de navegación que se encuentra. Resuelve que el uso de este código en lugar

UINavigationController *nav = self.navigationController; 
[self.navigationController popToRootViewControllerAnimated:NO]; 
[nav pushViewController:viewThreadController animated:YES]; 

también creo que esto suele resolver todo el problema. Probablemente recibirá un error que indica que dos estallidos y empujones rápidos pueden invalidar NavigationController.
Y para resolverlo, puede presionar NavigationController en el método viewDidDissappear del 2nd View Controller o presionarlo en el método viewDidAppear en el controlador de vista principal (lista de elementos).

+0

Mis conocimientos: cuando se utiliza animación: SÍ, entonces no funciona como se esperaba, pero animado: NO hace el trabajo. Y como popToRoot es más corto, lo usé. ¡Espero eso ayude! – kjoelbro

+0

Simplemente usar popToRootController es la respuesta aquí, creo.No es necesario hacer nada divertido con la vista. La pila y los empujes del controlador pueden funcionar normalmente como siempre. –

36

Si he entendido bien, usted tiene una pila de controladores de vista:

A (root) - B - C - D - E 

Y quiere que se convierta en:

A (root) - F 

derecho? En ese caso:

NSArray *viewControllers = self.navigationController.viewControllers; 
NSMutableArray *newViewControllers = [NSMutableArray array]; 

// preserve the root view controller 
[newViewControllers addObject:[viewControllers objectAtIndex:0]]; 
// add the new view controller 
[newViewControllers addObject:viewThreadController]; 
// animatedly change the navigation stack 
[self.navigationController setViewControllers:newViewControllers animated:YES]; 
+0

Esto se animará desde la vista E para ver F. –

+2

^@LysannSchlegel ese es el punto. Se anima desde E-> F, pero luego, si presiona el botón Atrás, irá a A en lugar de a E. Básicamente, borrará la pila posterior hasta la vista principal sin ninguna animación funky/inesperada. – DiscDev

+1

La respuesta de Dave es excelente, llévela al siguiente nivel de reutilización con una Categoría en UINavigationController: http://stackoverflow.com/a/25771209/1103584 – DiscDev

5

Compartiendo una categoría en UINavigationController basado en la respuesta de Dave DeLong que utilizamos en nuestra aplicación para mantener el botón de retroceso siempre funcionando según sea necesario.

@implementation UINavigationController (PushNewAndClearNavigationStackToParent) 

- (void) pushNewControllerAndClearStackToParent:(UIViewController*)newCont animated:(BOOL)animated 
{ 
    NSArray *viewControllers = self.viewControllers; 
    NSMutableArray *newViewControllers = [NSMutableArray array]; 
     
    // preserve the root view controller 
    [newViewControllers addObject:[viewControllers firstObject]]; 
    // add the new view controller 
    [newViewControllers addObject:newCont]; 
    // animatedly change the navigation stack 
    [self setViewControllers:newViewControllers animated:animated]; 
} 

@end 
1
NSArray *viewControllers = self.navigationController.viewControllers; 
NSMutableArray *newViewControllers = [NSMutableArray array]; 

// preserve the root view controller 
for(int i = 0; i < [viewControllers count];i++){ 
    if(i != [viewControllers count]-1) 
     [newViewControllers addObject:[viewControllers objectAtIndex:i]]; 
} 
// add the new view controller 
[newViewControllers addObject:conversationViewController]; 
// animatedly change the navigation stack 
[self.navigationController setViewControllers:newViewControllers animated:YES]; 
+0

¿Podría por favor elaborar más su respuesta agregando un poco más de descripción acerca de la solución que proporciona? – abarisone

0

que utilizan la respuesta de Dave de inspiración e hizo esto para Swift:

let newViewControllers = NSMutableArray() 
newViewControllers.addObject(HomeViewController()) 
newViewControllers.addObject(GroupViewController()) 
let swiftArray = NSArray(array:newViewControllers) as! Array<UIViewController> 
self.navigationController?.setViewControllers(swiftArray, animated: true) 
  1. Reemplazar HomeViewController() con lo que usted quiere que su controlador de vista inferior sea
  2. Reemplazar GroupViewController() con lo que quiera que su controlador de vista superior sea
0

Si lo que quiere hacer es navegar de alguna manera dentro del mismo controlador de navegación ... puede acceder a la barra de navegación A.K.A. viewControllers y luego configure los viewcontrollers en el orden que desee, o agregue o elimine algunos ... Esta es la forma más limpia y nativa de hacerlo.

 UINavigationController* theNav = viewControllerToDismiss.navigationController; 
     UIViewController* theNewController = [UIViewController new]; 
     UIViewController* rootView = theNav.viewControllers[0]; 
     [theNav setViewControllers:@[ 
            rootView, 
            theNewController 
            ] animated:YES]; 

haga las validaciones necesarias para que no obtenga ninguna excepción.

Cuestiones relacionadas