Jak wyświetlić jednocześnie dwa widoki z kontrolera nawigacyjnego?


92

Chcę przejść do trzeciego widoku stosu nawigacyjnego z powrotem do pierwszego widoku.

Wiem, jak wyświetlić jeden widok naraz:

[self.navigationController popViewControllerAnimated:YES];

Ale jak mam zrobić dwa na raz?


2
Komentarz meta: @lubilis odpowiedź jest najlepsza. Najwyżej ocenione odpowiedzi były w swoim czasie dobre, ale nie są już aktualne.
n13

Odpowiedzi:


133

Możesz spróbować również przeskoczyć między stosem kontrolera nawigacji

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

6
imo to zdecydowanie najlepsza metoda, ale powinieneś odwoływać się do kontrolera uinavigation za pomocą self.navigationcontroller
henghonglee

2
Zgadzam się, jest to najlepsze rozwiązanie, jeśli użytkownik chciałby przenieść stos z powrotem do określonego kontrolera widoku. Powiedzmy, że nie wiesz, który kontroler widoku to znaczy, nadal możesz zaimplementować system, w którym możesz określić, ile kontrolerów widoku chcesz wyrzucić ze stosu i pobrać docelowy kontroler widoku z tablicy allViewControllers z objectAtIndex: (allViewControllers.count - 1 - kwota). -1, ponieważ tablice są oczywiście liczone od zera.
Jovan

1
Uwielbiam to rozwiązanie. Dokładnie to, czego szukałem
Designer023

3
Działa również podczas iteracji po oryginalnej tablicy navigator-> viewControllers (nie ma potrzeby konwertowania jej na zmienną tablicę)
Arik Segal

UWAGA! To spowoduje iterację stosu od początku -> do końca, aby być dokładnie poprawnym, należy odwrócić stos. Ponieważ jeśli masz kilka VC tego samego rodzaju, usuniesz niewłaściwy VC w złej kolejności w stosie.
StackUnderflow

72

Oto dwa UINavigationControllerrozszerzenia, które mogą rozwiązać Twój problem. Poleciłbym użyć pierwszego, który pojawia się UIViewControllerna określonej klasie:

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

}

i użyj go w ten sposób:

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

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

3
W przypadku języka Swift (opcja 1) można zamienić te dwa na removeLastjust removeLast(2).
Dominic K

A co z wywoływaniem metod cyklu życia kontrolerów? DidAppear and ect
Mike Glukhov

1
(Swift 4) Brakuje nawiasów w tej linii let vc = viewControllers[viewControllers.count - viewsToPop + 1], aby działać poprawnie musisz je zastąpić: let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]lublet vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav

@MMiroslav masz rację. Zaktualizowałem odpowiedź. Dziękuję / Hvala;)
budidino

1
Ta odpowiedź została zaktualizowana po zamieszczeniu mojej odpowiedzi poniżej. Zasadniczo kopia mojego kodu ^ _ ^
lubilis

44

Możesz przejść do "głównego" (pierwszego) kontrolera widoku za pomocą popToRootViewControllerAnimated:

[self.navigationController popToRootViewControllerAnimated:YES];

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

UINavigationControllerOdniesienie :

Zdejmuje wszystkie kontrolery widoku na stosie z wyjątkiem głównego kontrolera widoku i aktualizuje wyświetlacz.

Wartość
zwracana Tablica kontrolerów widoku, które są zdejmowane ze stosu.


1
ha, nie mogę uwierzyć, że tak długo szukałem tak prostej odpowiedzi, dzięki!
Adam Waite

1
Swift 3: self.navigationController? .PopToRootViewController (animated: true);
dianakarenms

Dokładnie to, czego szukałem!
Canucklesandwich

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

objectAtIndex: 1 -> możesz przekazać dowolny indeks, do którego chcesz przeskoczyć


Dzięki za sztuczkę, chciałem zrobić to źle.
Linus,

18

Swift 2 - xCode 7.3.1

To może być bardzo przydatne rozszerzenie do uruchamiania 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
To wymaga więcej głosów poparcia ... Właśnie miałem napisać to rozszerzenie. Po prostu wykorzystam twoje podziękowania;)
n13

1
@ n13 dlaczego to jest lepsze niż odpowiedź budidino?
Crashalot

1
Użycie rozszerzenia zapewnia znacznie czystszy kod. Możesz wziąć odpowiedź budidino i rozszerzyć ją, ale ta oszczędza ci wysiłku. Również ta odpowiedź sprawdza przypadki błędów i z wdziękiem obsługuje błędy (np.
Próba

1
Podoba mi się ta odpowiedź. Zmusił mnie do przemyślenia i zaktualizowania opublikowanej odpowiedzi. Mój kod pojawił się w ostatnim wystąpieniu szukanej klasy w tablicy viewControllers, ponieważ jest to prawdopodobnie pożądane zachowanie.
budidino

15

Jeśli chcesz po prostu uruchomić 2 naraz, ponieważ twój rootViewController jest (o wiele) `` głębszy '', możesz rozważyć dodanie kategorii do UIviewController, na przykład:

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

Zaimportuj kategorię #import "UINavigationController+popTwice.h"gdzieś w swojej implementacji i użyj tego wiersza kodu, aby uruchomić 2 kontrolery naraz:

[self.navigationController popTwoViewControllersAnimated:YES];

czy to nie wspaniałe? :)


6
co jeśli chcesz otworzyć trzy widoki, napiszesz „UINavigationController + popThrice.m” ??????
Spotkaj się

8
możesz po prostu przekazać parametr określający liczbę viewControllerów do wyskoczenia i zawinąć [self popViewControllerAnimated: NO]; w pętli for licznik-1.
noRema

To nie jest właściwy sposób, jeśli chcesz potrącić do 2,3, ... dowolny kontroler zidentyfikuje go w pętli, a następnie użyj [self.navigationController popToViewControllerAnimated: YES] ;. Wspomniane powyżej jest bardzo złym kodowaniem i może powodować migotanie interfejsu użytkownika i złe wrażenia użytkownika.
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)
    }
}

Następnie użyj tej metody

self.popViewControllerss(popViews: 2)

Dobry, czego szukałem. Dziękuję.
maddysan

6

Możesz także spróbować tego: -

[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

W Swift 3 możesz w ten sposób zdjąć jeden, dwa lub więcej kontrolerów widoku z kontrolera nawigacyjnego

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

Tutaj FromWhereYouWantToGoController jest kontrolerem docelowym. Mam nadzieję, że to pomoże.


3

Możesz przekazać początkowy kontroler widoku (ten, do którego chcesz wrócić), a następnie wywołać tę linię w ostatnim widoku:

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

L.


3

Nie widziałem tutaj tej odpowiedzi. Jeśli chcesz pobrać tylko kilka (nie do samego katalogu głównego), możesz po prostu wykonać iterację przez self.navigationController.viewControllers sprawdzanie typów klas lub jeśli masz odniesienie, użyj tego:

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

2

możesz wrócić do głównego kontrolera widoku

[self.navigationController popToRootViewControllerAnimated:YES];

lub, jeśli widok, do którego chcesz się przeskoczyć, nie jest pierwszym, będziesz musiał ponownie wyświetlić widok w widoku poprzedniego widoku


2

Oto mała funkcja, której używam, aby wrócić do 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

Wersja Swift z (Swift 1.2 / Xcode 6.3.1) poppingu dwukrotnie lub więcej

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

lub

 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

Możesz użyć stosu UIViewControllers. 1. Pobierz tablicę wszystkich viewControllerów ze stosu. 2. Przejdź przez całą tablicę i znajdź żądany kontroler viewController
, dopasowując typ klasy. 3. Otwórz 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

Korzystanie z prostego rozszerzenia UINavigationController :

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.