Wie kann ich zwei Ansichten gleichzeitig von einem Navigationscontroller aus anzeigen?

89

Ich möchte zur dritten Ansicht im Navigationsstapel zurückkehren und zur ersten Ansicht zurückkehren.

Ich weiß, wie man eine Ansicht auf einmal öffnet:

[self.navigationController popViewControllerAnimated:YES];

Aber wie mache ich zwei gleichzeitig?

Adam Waite
quelle
2
Metakommentar: @lubilis antworte ganz unten, es ist das Beste. Die am besten bewerteten Antworten waren zu ihrer Zeit gut, aber nicht mehr relevant.
n13

Antworten:

132

Sie können dies versuchen, um auch zwischen dem Navigationscontroller-Stapel zu springen

NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
    if ([aViewController isKindOfClass:[RequiredViewController class]]) {
        [self.navigationController popToViewController:aViewController animated:NO];
    }
}
Treffen
quelle
6
Imo ist dies bei weitem die beste Methode, aber Sie sollten Ihren Uinavigation Controller mit self.navigationcontroller
henghonglee
2
Ich bin damit einverstanden, dass dies die beste Lösung ist, wenn der Benutzer den Stapel auf einen bestimmten Viewcontroller zurücksetzen möchte. Angenommen, Sie wissen nicht, um welchen Viewcontroller es sich handelt. Sie können dennoch ein System implementieren, in dem Sie angeben, wie viele Viewcontroller Sie vom Stapel entfernen und den Ziel-Viewcontroller mit objectAtIndex aus dem allViewControllers-Array abrufen möchten: (allViewControllers.count - 1 - Betrag). -1, weil Arrays natürlich auf Null basieren.
Jovan
1
Ich liebe diese Lösung. Genau das, wonach ich gesucht habe
Designer023
3
Funktioniert auch beim Durchlaufen des ursprünglichen Navigator-> viewControllers-Arrays (keine Konvertierung in ein veränderliches Array erforderlich)
Arik Segal
HINWEIS! Damit dies den Stapel vom Anfang -> bis zum Ende durchläuft, sollten Sie den Stapel umkehren, um genau zu sein. Denn wenn Sie mehrere VCs derselben Art haben, entfernen Sie die falschen VCs in der falschen Reihenfolge im Stapel.
StackUnderflow
69

Hier sind zwei UINavigationControllerErweiterungen, die Ihr Problem lösen können. Ich würde empfehlen, die erste zu verwenden, die zu UIViewControllereiner bestimmten Klasse gehört:

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)
    }
  }

}

und benutze es so:

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

// pop 2 view controllers
navigationController?.popViewControllers(viewsToPop: 2)
Budidino
quelle
3
Für Swift (Option 1) können Sie die beiden removeLastdurch just ersetzen removeLast(2).
Dominic K
Was ist mit dem Aufrufen von Methoden des Lebenszyklus von Controllern? DidAppear und ect
Mike Glukhov
1
(Swift 4) Sie vermissen Klammern in dieser Zeile let vc = viewControllers[viewControllers.count - viewsToPop + 1], um richtig zu funktionieren, müssen Sie es ersetzen durch: let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]oderlet vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav
@MMiroslav du hast recht. Ich habe meine Antwort aktualisiert. Vielen Dank / Hvala;)
Budidino
1
Diese Antwort wurde aktualisiert, nachdem ich meine Antwort unten gepostet habe. Im Wesentlichen eine Kopie meines Codes ^ _ ^
lubilis
44

Sie können zum (ersten) "Root" -Ansichts-Controller wechseln mit popToRootViewControllerAnimated:

[self.navigationController popToRootViewControllerAnimated:YES];

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

UINavigationControllerReferenz :

Öffnet alle View Controller auf dem Stack mit Ausnahme des Root View Controllers und aktualisiert die Anzeige.

Rückgabewert
Ein Array von Ansichtscontrollern, die vom Stapel entfernt werden.

chown
quelle
1
ha, ich kann nicht glauben, dass ich so lange nach einer so einfachen Antwort gesucht habe, danke!
Adam Waite
1
Swift 3: self.navigationController? .PopToRootViewController (animiert: true);
Dianakarenms
Genau das, wonach ich gesucht habe!
Canucklesandwich
29
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];   

objectAtIndex: 1 -> Sie können den gewünschten Index übergeben

Zaraki
quelle
Danke für den Trick, ich wollte es gerade falsch machen.
Linus
18

Swift 2 - xCode 7.3

Dies könnte eine sehr nützliche Erweiterung für Pop-UIViewController sein:

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")
        }
    }
}
lubilis
quelle
2
Dies erfordert mehr Upvoting. Ich wollte gerade diese Erweiterung schreiben. Ich benutze nur
deinen
1
@ n13 wie kommt es, dass dies besser ist als Budidinos Antwort?
Crashalot
1
Die Verwendung einer Erweiterung sorgt für viel saubereren Code. Sie könnten die Antwort von Budidino nehmen und daraus eine Erweiterung machen, aber diese erspart Ihnen die Mühe. Auch diese Antwort
sucht nach Fehlerfällen
1
Ich mag diese Antwort. Ich musste die Antwort, die ich gepostet habe, überdenken und aktualisieren. Ich habe meinen Code auf die letzte Instanz der gesuchten Klasse im viewControllers-Array verschoben, da dies wahrscheinlich das gewünschte Verhalten ist.
Budidino
15

Wenn Sie nur 2 auf einmal popen möchten, weil Ihr rootViewController (viel) tiefer ist als 2, können Sie UIviewController beispielsweise eine Kategorie hinzufügen:

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

Importieren Sie die Kategorie #import "UINavigationController+popTwice.h"irgendwo in Ihre Implementierung und verwenden Sie diese Codezeile, um 2 Controller gleichzeitig zu platzieren:

[self.navigationController popTwoViewControllersAnimated:YES];

ist das nicht toll :) :)

Tieme
quelle
6
Was ist, wenn Sie drei Ansichten öffnen müssen, schreiben Sie "UINavigationController + popThrice.m" ??????
Treffen Sie den
8
Sie können einfach einen Parameter für die Anzahl der zu öffnenden viewController übergeben und [self popViewControllerAnimated: NO] umbrechen. innerhalb einer for-Schleife von count-1.
noRema
Dies ist nicht der richtige Weg, wenn Sie auf 2,3 setzen möchten, ... jeder Controller identifiziert ihn durch eine Schleife und verwendet dann [self.navigationController popToViewControllerAnimated: YES];. Dies ist eine sehr schlechte Codierung und kann eine flackernde Benutzeroberfläche und eine schlechte Benutzererfahrung zeigen.
Vicky Dhas
10

Swift 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)
    }
}

Verwenden Sie dann diese Methode

self.popViewControllerss(popViews: 2)
Saifan Nadaf
quelle
Gut, was ich gesucht habe. Danke.
Maddysan
6

Sie können auch Folgendes ausprobieren: -

[self.navigationController popToViewController:yourViewController animated:YES];
Leena
quelle
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];
Sabareesh
quelle
4
    NSMutableArray *newStack = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
    [newStack removeLastObject];
    [newStack removeLastObject];
    [self.navigationController setViewControllers:newStack animated:YES];
patrick-fitzgerald
quelle
4

In Swift 3 können Sie einen, zwei oder mehr Viewcontroller auf diese Weise aus dem Navigationscontroller entfernen

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

Hier ist FromWhereYouWantToGoController der Zielcontroller. Ich hoffe es hilft.

Riajur Rahman
quelle
3

Sie können den anfänglichen Ansichts-Controller (den, zu dem Sie zurückkehren möchten) übergeben und diese Zeile in der letzten Ansicht aufrufen:

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

L. L.

Lucas
quelle
3

Ich habe diese Antwort hier nicht gesehen. Wenn Sie nur einige wenige (nicht bis zum Stammverzeichnis) einfügen möchten, können Sie einfach durch self.navigationController.viewControllers iterieren und nach Klassentypen suchen. Wenn Sie eine Referenz haben, verwenden Sie Folgendes:

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

Sie können zum Root View Controller zurückkehren

[self.navigationController popToRootViewControllerAnimated:YES];

Wenn die Ansicht, in die Sie einblenden möchten, nicht die erste ist, müssen Sie sie in viewWillAppear Ihrer vorherigen Ansicht erneut einfügen

Robotnik
quelle
2

Hier ist eine kleine Funktion, mit der ich X ViewController zurückkehre:

-(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];
    }
}
Kennzeichen
quelle
2

Swift-Version ab (Swift 1.2 / Xcode 6.3.1) zweimal oder öfter

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

oder

 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)
Glenn S.
quelle
1

Sie können den Stapel der UIViewController verwenden. 1. Rufen Sie das Array aller viewController im Stapel ab. 2. Durchlaufen Sie das gesamte Array und suchen Sie den gewünschten viewController,
indem Sie den Klassentyp abgleichen. 3. Öffnen Sie den 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)
            }
        }
}
Peeyush Karnwal
quelle
0

Verwenden einer einfachen UINavigationController-Erweiterung :

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
Balázs Vincze
quelle