¿Cómo abro dos vistas a la vez desde un controlador de navegación?


90

Quiero ir a la tercera vista de la pila de navegación y volver a la primera vista.

Sé cómo abrir una vista a la vez:

[self.navigationController popViewControllerAnimated:YES];

¿Pero cómo hago dos a la vez?


2
Meta comentario: @lubilis responde hasta el final es el mejor. Las respuestas mejor calificadas fueron buenas en su momento, pero ya no son relevantes.
— n13

Respuestas:


132

También puede probar esto para saltar entre la pila del controlador de navegación

NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
    if ([aViewController isKindOfClass:[RequiredViewController class]]) {
        [self.navigationController popToViewController:aViewController animated:NO];
    }
}

6
En mi opinión, este es el mejor método con diferencia, pero debe hacer referencia a su controlador de navegación uina utilizando self.navigationcontroller
— henghonglee

2
Estoy de acuerdo, esta es la mejor solución si el usuario desea devolver la pila a un cierto controlador de vista. Digamos que no sabe qué viewcontroller es ese, aún puede implementar un sistema en el que especifique cuántos viewcontrollers le gustaría sacar de la pila y obtener el viewcontroller de destino de la matriz allViewControllers con objectAtIndex: (allViewControllers.count - 1 - cantidad). -1 porque las matrices son de base cero, por supuesto.
— Jovan

1
Amo esta solución. Exactamente lo que estaba buscando
— Designer023

3
Funciona también cuando se itera sobre el navegador original-> matriz viewControllers (no es necesario convertirla en una matriz mutable)
— Arik Segal

¡NOTA! Que esto iterará la pila desde el principio -> hasta el final, para ser exactamente correcto, debe invertir la pila. Porque si tiene varios VC del mismo tipo, eliminará el VC incorrecto en el orden incorrecto de la pila.
— StackUnderflow

71

Aquí hay dos UINavigationControllerextensiones que pueden resolver su problema. Recomendaría usar el primero que aparece en una UIViewControllerclase específica:

extension UINavigationController {

  func popToViewController(ofClass: AnyClass, animated: Bool = true) {
    if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
      popToViewController(vc, animated: animated)
    }
  }

  func popViewControllers(viewsToPop: Int, animated: Bool = true) {
    if viewControllers.count > viewsToPop {
      let vc = viewControllers[viewControllers.count - viewsToPop - 1]
      popToViewController(vc, animated: animated)
    }
  }

}

y utilícelo así:

// pop to SomeViewController class
navigationController?.popToViewController(ofClass: SomeViewController.self)

// pop 2 view controllers
navigationController?.popViewControllers(viewsToPop: 2)

3
Para Swift (opción 1), puede reemplazar los dos removeLastcon solo removeLast(2).
— Dominic K

¿Qué pasa con los métodos de llamada del ciclo de vida de los controladores? DidAparecer y ect
— Mike Glukhov

1
(Swift 4) Le faltan corchetes en esta línea let vc = viewControllers[viewControllers.count - viewsToPop + 1], para que funcione correctamente debe reemplazarlo con: let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]olet vc = viewControllers[viewControllers.count - viewsToPop - 1]
— MMiroslav

@MMiroslav tienes razón. Actualicé mi respuesta. Gracias / Hvala;)
— budidino

1
Esta respuesta se ha actualizado después de publicar mi respuesta a continuación. Esencialmente una copia de mi código ^ _ ^
— lubilis

44

Puede ir al controlador de vista "raíz" (primer) con popToRootViewControllerAnimated:

[self.navigationController popToRootViewControllerAnimated:YES];

// If you want to know what view controllers were popd:
// NSArray *popdViewControllers = [self.navigationController popToRootViewControllerAnimated:YES];

UINavigationControllerReferencia :

Muestra todos los controladores de vista de la pila, excepto el controlador de vista raíz, y actualiza la pantalla.

Valor de retorno
Una matriz de controladores de vista que se extraen de la pila.


1
ja, no puedo creer que haya pasado tanto tiempo buscando una respuesta tan simple, ¡gracias!
— Adam Waite

1
Swift 3: self.navigationController? .PopToRootViewController (animado: verdadero);
— dianakarenms

¡Precisamente lo que estaba buscando!
— Canucklesandwich

29
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];   

objectAtIndex: 1 -> puede pasar el índice al que desee aparecer


Gracias por el truco, estaba a punto de hacerlo mal.
— Linus

18

Swift 2 - xCode 7.3

Esta podría ser una extensión muy útil para desplegar UIViewControllers:

extension UINavigationController {

    func popToViewControllerOfType(classForCoder: AnyClass) {
        for controller in viewControllers {
            if controller.classForCoder == classForCoder {
                popToViewController(controller, animated: true)
                break
            }
        }
    }

    func popViewControllers(controllersToPop: Int, animated: Bool) {
        if viewControllers.count > controllersToPop {
            popToViewController(viewControllers[viewControllers.count - (controllersToPop + 1)], animated: animated)
        } else {
            print("Trying to pop \(controllersToPop) view controllers but navigation controller contains only \(viewControllers.count) controllers in stack")
        }
    }
}

2
Esto necesita más votos a favor ... Estaba a punto de escribir esa extensión. Solo
— usaré el

1
@ n13 ¿cómo es que esto es mejor que la respuesta de budidino?
— Crashalot

1
Usar una extensión hace que el código sea mucho más limpio. Podrías tomar la respuesta de Budidino y hacer una extensión de ella, pero esta te ahorra el esfuerzo. Además, esta respuesta verifica los casos de error y maneja los errores con elegancia (por ejemplo, tratando de
— abrir

1
Me gusta esta respuesta. Me hizo repensar y actualizar la respuesta que publiqué. Hice que mi código apareciera en la última instancia de la clase buscada en la matriz viewControllers porque ese es probablemente el comportamiento deseado.
— Budidino

15

Si solo desea hacer estallar 2 a la vez porque su rootViewController es (mucho) 'más profundo', entonces 2 podría considerar agregar una categoría a UIviewController, por ejemplo:

UINavigationController + popTwice.h

#import <UIKit/UIKit.h>
@interface UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated;

@end

UINavigationController + popTwice.m

#import "UINavigationController+popTwice.h"

@implementation UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated{
    [self popViewControllerAnimated:NO];
    [self popViewControllerAnimated:animated];
}

@end

Importe la categoría #import "UINavigationController+popTwice.h"en algún lugar de su implementación y use esta línea de código para extraer 2 controladores a la vez:

[self.navigationController popTwoViewControllersAnimated:YES];

¿no es genial? :)


6
¿Qué pasa si necesitas abrir tres vistas, escribirás "UINavigationController + popThrice.m" ??????
— Encuentro el

8
podría simplemente pasar un parámetro para el número de viewControllers que aparecerán y envolver [self popViewControllerAnimated: NO]; dentro de un bucle for, de count-1.
— noRema

Ésta no es la forma correcta, si desea colocar el potenciómetro en 2,3, ... cualquier controlador lo identifica por bucle y luego usa [self.navigationController popToViewControllerAnimated: YES] ;. Esto mencionado anteriormente es una codificación muy mala y puede mostrar una interfaz de usuario parpadeante y una mala experiencia de usuario.
— Vicky Dhas

10

Rápido 4:

func popViewControllerss(popViews: Int, animated: Bool = true) {
    if self.navigationController!.viewControllers.count > popViews
    {
        let vc = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - popViews - 1]
         self.navigationController?.popToViewController(vc, animated: animated)
    }
}

Entonces usa este método

self.popViewControllerss(popViews: 2)

Buena, lo que estaba buscando. Gracias.
— maddysan

6

También puedes probar este: -

[self.navigationController popToViewController:yourViewController animated:YES];

6
//viewIndex = 1;
//viewIndex = 2;
//viewIndex = 3;

// **[viewControllers objectAtIndex: *put here your viewindex number*]

NSArray *viewControllers = [self.navigationController viewControllers];
[self.navigationController popToViewController:[viewControllers objectAtIndex:viewIndex] animated:NO];

4
    NSMutableArray *newStack = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
    [newStack removeLastObject];
    [newStack removeLastObject];
    [self.navigationController setViewControllers:newStack animated:YES];

4

En Swift 3 , puede sacar uno, dos o más controladores de vista desde el controlador de navegación de esa manera

let viewControllers = self.navigationController!.viewControllers as [UIViewController]
    for aViewController:UIViewController in viewControllers {
        if aViewController.isKind(of: FromWhereYouWantToGoController.self) {
            _ = self.navigationController?.popToViewController(aViewController, animated: true)
        }
    }

Aquí FromWhereYouWantToGoController es el controlador de destino. Espero eso ayude.


3

Puede pasar el controlador de vista inicial (al que desea volver) y luego llamar a esta línea en la última vista:

[self.navigationController popToViewController:yourInitialViewController animated:YES];

L.


3

No vi esta respuesta aquí. Si solo desea mostrar algunos (no todo el camino hasta la raíz), puede iterar a través de self.navigationController.viewControllers verificando los tipos de clases, o si tiene una referencia, use eso:

for (UIViewController *aViewController in self.navigationController.viewControllers) {
   if ([aViewController isKindOfClass:[SMThumbnailViewController class]]) {
      [self.navigationController popToViewController:aViewController animated:YES];
   }
}

2

puede volver al controlador de vista raíz

[self.navigationController popToRootViewControllerAnimated:YES];

o, si la vista a la que desea aparecer no es la primera, deberá volver a aparecer en la vista de la vista anterior.


2

Aquí hay una pequeña función que estoy usando para volver a X ViewControllers:

-(void)backMultiple:(id)data {
    int back = 2; //Default to go back 2 
    int count = [self.navigationController.viewControllers count];

    if(data[@"count"]) back = [data[@"count"] intValue];

    //If we want to go back more than those that actually exist, just go to the root
    if(back+1 > count) {
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    //Otherwise go back X ViewControllers 
    else {
        [self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:count-(back+1)] animated:YES];
    }
}

2

Versión Swift a partir de (Swift 1.2 / Xcode 6.3.1) de hacer estallar dos veces o más

 var viewControllers = self.navigationController?.viewControllers
 viewControllers?.removeLast()
 viewControllers?.removeLast()
 self.navigationController?.setViewControllers(viewControllers, animated: true)

o

 var viewControllers = self.navigationController?.viewControllers
 var viewsToPop = 2
 var end = (viewControllers?.count)!
 var start = end - viewsToPop
 viewControllers?.removeRange(Range<Int>(start: start, end: end))
 self.navigationController?.setViewControllers(viewControllers, animated: true)

1

Puede utilizar la pila de UIViewControllers. 1. Obtenga la matriz de todos los viewControllers de la pila. 2. Itere a través de toda la matriz y busque el viewController deseado haciendo
coincidir el tipo de clase. 3. Pop el viewController.

func popToSpecificViewC
{
let viewControllers: [UIViewController] = self.navigationController!.viewControllers as [UIViewController];
        for viewController:UIViewController in viewControllers
        {
            if viewController.isKind(of: WelcomeViewC.self)
            {
                _ = self.navigationController?.popToViewController(viewController, animated: true)
            }
        }
}

0

Usando una extensión UINavigationController simple :

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.