Come faccio a visualizzare due visualizzazioni contemporaneamente da un controller di navigazione?


90

Voglio tornare alla terza vista nello stack di navigazione alla prima vista.

So come visualizzare una visualizzazione alla volta:

[self.navigationController popViewControllerAnimated:YES];

Ma come ne faccio due contemporaneamente?


2
Meta commento: la risposta di @lubilis fino in fondo è la migliore. Le risposte più votate erano buone ai loro tempi ma non sono più rilevanti.
n13

Risposte:


132

Puoi provare questo anche per saltare tra lo stack del controller di navigazione

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 questo è di gran lunga il metodo migliore, ma dovresti fare riferimento al tuo controller di navigazione usando self.navigationcontroller
henghonglee

2
Sono d'accordo, questa è la soluzione migliore se l'utente desidera riportare lo stack su un determinato viewcontroller. Supponiamo che tu non sappia quale viewcontroller sia, puoi ancora implementare un sistema in cui devi specificare quanti viewcontroller desideri estrarre dallo stack e ottenere il viewcontroller di destinazione dall'array allViewControllers con objectAtIndex: (allViewControllers.count - 1 - importo). -1 perché gli array sono ovviamente a base zero.
Jovan

1
Amo questa soluzione. Esattamente quello che stavo cercando
Designer023

3
Funziona anche durante l'iterazione sull'array originale navigator-> viewControllers (non è necessario convertirlo in un array modificabile)
Arik Segal

NOTA! Che questo itererà lo stack dall'inizio -> alla fine, per essere esattamente corretto dovresti invertire lo stack. Perché se hai diversi VC dello stesso tipo, rimuoverai il VC sbagliato nell'ordine sbagliato nello stack.
StackUnderflow

71

Ecco due UINavigationControllerestensioni che possono risolvere il tuo problema. Consiglierei di usare il primo che compare in una UIViewControllerdi una classe specifica:

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

}

e usalo in questo modo:

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

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

3
Per Swift (opzione 1), puoi sostituire i due removeLastcon solo removeLast(2).
Dominic K

Che dire della chiamata ai metodi del ciclo di vita dei controller? DidAppear and ect
Mike Glukhov

1
(Swift 4) Mancano le parentesi quadre in questa riga let vc = viewControllers[viewControllers.count - viewsToPop + 1], per funzionare correttamente è necessario sostituirlo con: let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]olet vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav

@ MMiroslav hai ragione. Ho aggiornato la mia risposta. Grazie / Hvala;)
budidino

1
Questa risposta è stata aggiornata dopo che ho pubblicato la mia risposta di seguito. Essenzialmente una copia del mio codice ^ _ ^
lubilis

44

Puoi accedere al controller di visualizzazione "root" (primo) con popToRootViewControllerAnimated:

[self.navigationController popToRootViewControllerAnimated:YES];

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

UINavigationControllerRiferimento :

Visualizza tutti i controller di visualizzazione sullo stack tranne il controller di visualizzazione principale e aggiorna la visualizzazione.

Valore restituito
Un array di controller di visualizzazione estratti dallo stack.


1
ah, non posso credere di aver passato così tanto tempo a cercare una risposta così semplice, grazie!
Adam Waite

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

Proprio quello che stavo cercando!
Canucklesandwich

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

objectAtIndex: 1 -> puoi passare qualsiasi indice a cui desideri eseguire il pop


Grazie per il trucco, stavo per farlo nel modo sbagliato.
Linus

18

Swift 2 - xCode 7.3

Questa potrebbe essere un'estensione molto utile per far apparire 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
Questo ha bisogno di più voti positivi ... Stavo per scrivere quell'estensione.
Userò

1
@ n13 come mai questa è migliore della risposta di budidino?
Crashalot

1
L'uso di un'estensione rende il codice molto più pulito. Potresti prendere la risposta di Budidino e farne un'estensione, ma questo ti fa risparmiare lo sforzo. Anche questa risposta controlla i casi di errore e gestisce gli errori con garbo (ad esempio, cercando di far
apparire

1
Mi piace questa risposta. Mi ha fatto ripensare e aggiornare la risposta che ho pubblicato. Ho fatto apparire il mio codice sull'ultima istanza della classe cercata nell'array viewControllers perché questo è probabilmente il comportamento desiderato.
budidino

15

Se vuoi solo pop 2 in una volta perché il tuo rootViewController è (molto) 'più profondo', quindi 2 potresti prendere in considerazione l'aggiunta di una categoria a UIviewController, ad esempio:

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

Importa la categoria #import "UINavigationController+popTwice.h"da qualche parte nella tua implementazione e utilizza questa riga di codice per visualizzare 2 controller contemporaneamente:

[self.navigationController popTwoViewControllersAnimated:YES];

non è fantastico? :)


6
cosa succede se hai bisogno di visualizzare tre viste, scrivi "UINavigationController + popThrice.m" ??????
Incontro il

8
potresti semplicemente passare un parametro per il numero di viewController da visualizzare e avvolgere [self popViewControllerAnimated: NO]; all'interno di un ciclo for, di count-1.
noRema

Questo non è il modo corretto, se vuoi passare a 2,3, ... qualsiasi controller lo identifica tramite loop e quindi usa [self.navigationController popToViewControllerAnimated: YES] ;. Ciò sopra menzionato è una codifica pessima e potrebbe mostrare un'interfaccia utente tremolante e una cattiva esperienza utente.
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)
    }
}

Quindi utilizzare questo metodo

self.popViewControllerss(popViews: 2)

Bene, quello che stavo cercando. Grazie.
maddysan

6

Puoi anche provare questo: -

[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

In Swift 3 , puoi far apparire uno, due o più viewcontroller dal controller di navigazione in questo modo

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

Here FromWhereYouWantToGoController è il controller di destinazione. Spero che sia d'aiuto.


3

Puoi passare il controller della vista iniziale (quello a cui vuoi tornare) e quindi chiamare questa riga nell'ultima vista:

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

L.


3

Non ho visto questa risposta qui. Se vuoi solo farne alcuni (non fino alla radice), puoi semplicemente iterare attraverso self.navigationController.viewControllers controllando i tipi di classe, o se hai un riferimento usa quello:

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

2

puoi tornare al controller della vista principale

[self.navigationController popToRootViewControllerAnimated:YES];

oppure, se la visualizzazione che desideri visualizzare non è la prima, dovrai visualizzarla di nuovo nella visualizzazione precedente.


2

Ecco una piccola funzione che sto usando per tornare indietro 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

Versione Swift a partire da (Swift 1.2 / Xcode 6.3.1) di popping due o più volte

 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

È possibile utilizzare lo stack degli UIViewControllers. 1. Recupera l'array di tutti i viewController nello stack. 2. Itera attraverso l'intero array e trova il viewController desiderato
facendo corrispondere il tipo di classe. 3. Apri il 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

Utilizzando una semplice estensione UINavigationController :

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.