¿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.