ナビゲーションコントローラーから一度に2つのビューをポップするにはどうすればよいですか?


90

ナビゲーションスタックの3番目のビューにポップして、最初のビューに戻したいです。

一度に1つのビューをポップする方法を知っています。

[self.navigationController popViewControllerAnimated:YES];

しかし、どうすれば一度に2つ実行できますか?


2
メタコメント:@lubilisは、一番下にあるすべての方法で回答します。最高評価の回答は当時は良好でしたが、関連性はなくなりました。
n13

回答:


132

これを試して、ナビゲーションコントローラスタック間をジャンプすることもできます。

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

6
これはこれまでで最高の方法ですが、self.navigationcontrollerを使用してuinavigationコントローラーを参照する必要があります
henghonglee

2
私が同意するのは、ユーザーがスタックを特定のビューコントローラーにポップバックしたい場合、これが最良のソリューションです。どのビューコントローラであるかがわからないとしましょう。スタックからポップしたいビューコントローラの数を指定し、objectAtIndex:(allViewControllers.count- 1-金額)。配列はゼロベースのコースであるため、-1。
Jovan

1
このソリューションが大好きです。まさに私が探していたもの
Designer023

3
元のnavigator-> viewControllers配列を反復するときにも機能します(可変配列に変換する必要はありません)
Arik Segal

注意!これがスタックを最初から最後まで繰り返す->正確に正しいためには、スタックを逆にする必要があります。同じ種類のVCが複数ある場合、スタック内の間違った順序で間違ったVCを削除するためです。
StackUnderflow 2017年

71

UINavigationController問題を解決できる2つの拡張機能を次に示します。UIViewController特定のクラスの最初にポップする最初のものを使用することをお勧めします:

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

}

次のように使用します。

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

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

3
Swift(オプション1)の場合、2つremoveLastを単にで置き換えることができますremoveLast(2)
ドミニクK

コントローラのライフサイクルのメソッドの呼び出しはどうですか?DidAppear and ect
Mike Glukhov

1
(Swift 4)この行let vc = viewControllers[viewControllers.count - viewsToPop + 1]にブラケットがありません。正しく機能するには、次のものと置き換える必要があります。let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]またはlet vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav

@MMiroslavあなたは正しいです。回答を更新しました。ありがとう/ Hvala;)
budidino 2018

1
この回答は、以下に回答を投稿した後に更新されました。基本的に私のコードのコピー^ _ ^
lubilis

44

「ルート」(最初)のビューコントローラーにポップすることができますpopToRootViewControllerAnimated

[self.navigationController popToRootViewControllerAnimated:YES];

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

UINavigationController参照

ルートビューコントローラーを除くスタック上のすべてのビューコントローラーをポップし、表示を更新します。

戻り値
スタックからポップされたビューコントローラーの配列。


1
ハ、私がそんなに簡単な答えを探して長い間費やしたなんて信じられない、ありがとう!
Adam Waite

1
Swift 3:self.navigationController?.popToRootViewController(animated:true);
dianakarenms 2017年

まさに私が探していたもの!
Canucklesandwich 2017

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

objectAtIndex:1->ポップするインデックスを渡すことができます


トリックをありがとう、私はちょうどそれを間違った方法でやろうとしていた。
Linus

18

Swift 2-xCode 7.3

これは、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
これにはもっと投票する必要があります。。私はちょうどその拡張を書こうとしていました。私はあなたの感謝を使うつもりです;)
n13

1
@ n13なぜこれがbudidinoの答えよりも優れているのですか?
Crashalot 2017年

1
拡張機能を使用すると、コードがよりクリーンになります。あなたはbudidinoの答えを取り、それから拡張することができますが、これはあなたの努力を節約します。また、この回答はエラーケースをチェックし、エラーを適切に処理します(たとえば、自分より多くポップしようとするなど)
n13

1
私はこの答えが好きです。投稿した回答を再考して更新しました。これはおそらく望ましい動作であるため、viewControllers配列内の検索されたクラスの最後のインスタンスにコードpopを作成しました。
budidino

15

rootViewControllerが(ウェイ)「より深い」ため、一度に2つをポップするだけの場合は、2をUIviewControllerに追加することを検討できます。次に例を示します。

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

#import "UINavigationController+popTwice.h"実装のどこかにカテゴリをインポートし、次のコード行を使用して、2つのコントローラーを一度にポップします。

[self.navigationController popTwoViewControllersAnimated:YES];

すごくないですか?:)


6
3つのビューをポップする必要がある場合は、「UINavigationController + popThrice.m」と記述しますか??????
会う

8
表示するviewControllersの数のパラメーターを渡し、[self popViewControllerAnimated:NO]をラップするだけです。count-1のforループ内。
noRema

これは正しい方法ではありません。2,3、...にポットしたい場合は、コントローラがループでそれを識別し、[self.navigationController popToViewControllerAnimated:YES];を使用します。上記のコードは非常に不適切であり、UIがちらついたり、ユーザーエクスペリエンスが低下したりすることがあります。
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)
    }
}

次に、この方法を使用します

self.popViewControllerss(popViews: 2)

良いもの、私が探していたもの。ありがとう。
maddysan

6

これも試すことができます:-

[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

Swift 3では、そのようなナビゲーションコントローラーから1つ、2つ、またはそれ以上のビューコントローラーをポップできます

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

ここFromWhereYouWantToGoControllerは宛先コントローラーです。それが役に立てば幸い。


3

最初のビューコントローラー(戻りたいコントローラー)を渡し、最後のビューで次の行を呼び出すことができます。

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

L


3

この答えはここにはありませんでした。(ルートまでのすべてではなく)いくつかをポップするだけの場合は、クラス型をチェックするself.navigationController.viewControllersを反復するか、参照にそれを使用する場合は、次のようにします。

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

2

ルートビューコントローラーにポップバックできます

[self.navigationController popToRootViewControllerAnimated:YES];

または、ポップしたいビューが最初のビューでない場合は、前のビューのviewWillAppearでもう一度ポップする必要があります。


2

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

2回以上ポップする(Swift 1.2 / Xcode 6.3.1)時点のSwiftバージョン

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

または

 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

UIViewControllersのスタックを使用できます。1.スタック内のすべてのviewControllerの配列をフェッチします。2.配列全体を反復処理
し、クラスタイプを照合して目的のviewControllerを見つけます。3. 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

単純なUINavigationController拡張機能を使用する:

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.